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 */
@GenerateNativeHeader
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_*
...
java_lang_Double.h
java_lang_Float.h
java_lang_Integer.h
java_lang_Long.h
java_lang_Object.h
java_lang_Package.h
...
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"
./jdk/src/java.base/unix/native/libnio/ch/FileChannelImpl.c
#include "java_lang_Integer.h"
./jdk/src/java.base/unix/native/libnio/ch/IOUtil.c
#include "java_lang_Integer.h"
./jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
#include "java_lang_Integer.h"
./jdk/src/java.base/windows/native/libnio/ch/FileChannelImpl.c
#include <java_lang_Integer.h>
./jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
like Long
find . \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Long.h" {} \; -print
#include "java_lang_Long.h"
./jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
like Float
find . \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Float.h" {} \; -print
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/Float.c
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/ObjectInputStream.c
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/ObjectOutputStream.c
and like Double
find . \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Double.h" {} \; -print
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/Double.c
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/ObjectInputStream.c
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/ObjectOutputStream.c
but neither Short
find . \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Short.h" {} \; -print
nor Byte
, nor Character
.
Conclusion
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
)