Can JNI call a method on an object during initialisation?
A java class does something like the following
public class Foo {
private final NativeCallbackHandler handler;
public Foo(NativeCallbackHandler handler) {
// I've shortened this for exposition, callSomeNativeMethod
// really happens in a superclass that I don't own (and is
// part of the lib that gives me the native part)
callSomeNativeMethod();
this.handler = handler;
}
public void handleNativeCallback(Object args) {
this.handler.callback(args);
}
private native int callSomeNativeMethod();
}
You can assume that the native method does something that can lead to native code calling handleNativeMethod
I have 2 related questions
- I believe the native code must call have a handle on this object and also call
GetMethodID
to get access to the method to call, is it possible for that na开发者_运维百科tive code to call the method before the object is fully initialised? - If it can, what are the semantics of an uninitialised final field?
if 1 is yes then I expect 2 to blow up on access it and hence I imagine we'd need to make it an AtomicReference
in order to access it safely without blowing up.
Note I have no control over the behaviour of the native library.
Looks like it is possible. Native code does not enforce the final
restriction.
From http://java.sun.com/docs/books/jni/html/pitfalls.html#36197:
10.9 Violating Access Control Rules
The JNI does not enforce class, field, and method access control restrictions that can be expressed at the Java programming language level through the use of modifiers such as private and final. It is possible to write native code to access or modify fields of an object even though doing so at the Java programming language level would lead to an IllegalAccessException. JNI's permissiveness was a conscious design decision, given that native code can access and modify any memory location in the heap anyway.
Native code that bypasses source-language-level access checks may have undesirable effects on program execution. For example, an inconsistency may be created if a native method modifies a final field after a just-in-time (JIT) compiler has inlined accesses to the field. Similarly, native methods should not modify immutable objects such as fields in instances of java.lang.String or java.lang.Integer. Doing so may lead to breakage of invariants in the Java platform implementation.
This doesn't define behavior when you access an uninitialized final reference, but we can probably make a fairly good guess.
Personally, I would try to avoid the problem, either by:
- Making sure everything was initialized before the callback
- Doing nothing during the callback until a flag was set that initialization was complete.
The call to handleNativeCallback
from a super class constructor will lead to a NullPointerException
, because it is invoked before the handler is set. There is no difference whether the call was made by JNI or pure Java code.
精彩评论