I understand the use of the @Native
annotation.
Indicates that a field defining a constant value may be referenced from native code. The annotation may be used as a hint by tools that generate native header files to determine whether a header file is required, and if so, what declarations it should contain.
However, while reading the java source code I noticed that in the class Integer
and Long
the SIZE
constant is @Native
while it is not for the Float, Byte, Double, Short and Character.
Note that the SIZE constant represents the number of bits used to represent the actual value.
public static final int SIZE = 8;//Byte
public static final int SIZE = 16;//Character
public static final int SIZE = 16;//Short
public static final int SIZE = 32;//Float
@Native public static final int SIZE = 32;//Integer
@Native public static final int SIZE = 64;//Long
public static final int SIZE = 64;//Double
Edit : I just noticed that this also applies for MAX_VALUE
and MIN_VALUE
of the same classes.
Edit 2 : I had spare time to do some research on this, and looking at the header files of the Long, Float etc. classes I had hope to figure out that the constants were not present in the other headers, but unfortunately they are.
static const jint SIZE = 8L;//java/lang/Byte.h
static const jint SIZE = 16L;//java/lang/Character.h
static const jint SIZE = 16L;//java/lang/Short.h
static const jint SIZE = 32L;//java/lang/Float.h
static const jint SIZE = 32L;//java/lang/Integer.h
static const jint SIZE = 64L;//java/lang/Double.h
static const jint SIZE = 64L;//java/lang/Long.h
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?
@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.
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
.
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
)
gontard got it right.
javac will (optionally) generate a native header file if a class contains native methods or fields annotated with @Native.
This was a new feature for javac in JDK 8, and is nothing to do with the Jigsaw module system, as some have conjectured. The JDK build system notes when javac has generated new/different native header files, and uses that to only trigger recompilation of native code when necessary.
Jonathan Gibbons, Oracle's javac team
Looking at the issue and fix, it looks like this has been done to resolve a handling of a header file generation for special classes in jigsaw
Jigsaw is a module system designated to use in Java SE Platform and JDK. More details here
Here is a corresponding changeset. You can see a comment,
Special handling of header file generation for classes in the jigsaw base module which currently can't add the annotaion GenerateNativeHeaders. For these specific classes the java file and the class have the same names which enables shortcutting the dependencies.
From the changeset I see that for the sake of purpose in addition tojava.lang.Integer
and java.lang.Long
, also some properties in java.net.SocketOptions
, sun.nio.ch.IOStatus
, java.io.FileSystem
have been changed to @Native
.
So I assume only those were needed to solve the dependency with jigsaw.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With