Why is the SIZE constant only @Native for Integer and Long?

TLDR: Jump to the conclusion

Why is the SIZE constant only @Native for Integer and Long?

A brief history of @Native

I made some search on the mailing lists. I found some interesting things.

At first an annotation (1 2) javax.tools.annotation.ForceNativeHeader
was introduced to

to trigger javah on a class.

It is used by com.sun.tools.javac.processing.NativeapiVisitor. By looking at the code we can see that the native header is generated if the class declare some native methods or if the class is annotated @ForceNativeHeader.

Later this annotation was renamed to GenerateNativeHeader (1 2).

Then this annotation was added to several types (especially Integer and Long) with an interresting comment:

/* No native methods here, but the constants are needed in the supporting JNI code */
public final class Long extends Number implements Comparable<Long> {...

But by adding this annotation it add a problematic dependency from base module to the module containing javax.tools. So the annotation were removed from Integer and Long and these files were explicitly added to the build process since the header were no more automatically generated… a “(hopefully temporary) hack”.

So a new annotation java.lang.annotation.Native was created and used in Integer and Long. The annotation was set a TargetType FIELD.

the annotation should be directly applied to the constant fields that need to be exported — and not to the class as a whole.

All the purpose of this stuff is:

javac could generate native headers for classes containing native methods.

It is the case of Integer and Long

this was a part of the JEP 139: Enhance javac to Improve Build Speed:

javah will be automatically run on any class that contains native methods and the generated C-headers will be put in the (-h) headerdir. A new annotation @ForceNativeHeader is used for classes that have final static primitives that need to be exported to JNI, but no native methods.

A basic experimentation

I made a basic experimentation on the JDK. I clone the open-jdk forest and i successfully build it. As expected the header files where generated for Integer and Long (thanks to @Native) and for Float and Double (thanks to their native methods) but not for Byte, Short

    ls -l build/macosx-x86_64-normal-server-release/support/headers/java.base/java_lang_*

Then i tried to remove the @Native from the Integer fields and i tried to build again the jdk but i get an error:

jdk/src/java.base/unix/native/libnio/ch/FileChannelImpl.c:35:10: fatal error: 'java_lang_Integer.h' file not found
#include "java_lang_Integer.h"
1 error generated.

logically since the header have not been generated.

I have also confirmed that java_lang_Integer.h is included in several c and cpp files:

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Integer.h" {} \; -print
#include "java_lang_Integer.h"
#include "java_lang_Integer.h"
#include "java_lang_Integer.h"
#include "java_lang_Integer.h"
#include <java_lang_Integer.h>

like Long

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Long.h" {} \; -print
#include "java_lang_Long.h"

like Float

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Float.h" {} \; -print
#include "java_lang_Float.h"
#include "java_lang_Float.h"
#include "java_lang_Float.h"

and like Double

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Double.h" {} \; -print
#include "java_lang_Double.h"
#include "java_lang_Double.h"
#include "java_lang_Double.h"

but neither Short

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Short.h" {} \; -print

nor Byte, nor Character.


Among all these types, only Integer, Long, Float, Double are used in the native source code of the jdk.

And only the Integer and Long fields are annotated with @Native because they have no native methods (as opposed to Float and Double)

Leave a Comment