Wednesday, September 12, 2007
Run your Java program as an NT service
You can browse the source here. A NetBeans project is included.
I was working on an abstract service class as well but Thomas beat me to completion. Great work, Thomas!
Update: Make sure your classpath and classes are accessible by the local system account, or the service won't be able to start. To see if this is the issue, you can temporarily change the service to start using your user identity; if it works, then the problem is that the local system account doesn't have access.
Thursday, September 06, 2007
Is final not final, or just not the final I wanted?
public class Pointer {
public static final int SIZE = Native.POINTER_SIZE;
}
public class Native {
public static final int POINTER_SIZE;
static {
initIDs();
POINTER_SIZE = pointerSize();
}
private static native int pointerSize();
}
I had just moved the native initialization code from Pointer to Native. All the native methods were private, so the only changes were to update those two classes and rename the native methods. But when I reran the test suite, I started getting a host of errors.
There errors were all caused by Pointer.SIZE having a zero value. I figured that since Pointer.SIZE was final, the value it was assigned from must also have been zero. A quick inspection on Native.POINTER_SIZE, however, showed that it was propertly initialized and non-zero. How, then, could Pointer.SIZE be zero if Native.POINTER_SIZE was not?
Anyone who has done any JNI is probably aware that Java access modifiers don't mean anything to native code. My first thought was that perhaps "final" modifiers don't mean anything either. Only problem is that I was never touching that Pointer.SIZE field in native code. Never even accessed it.
Scanning though the native initialization code, I noticed that, among a host of standard JRE classes, a reference to the Pointer class was being created. This turns out to be the cause of my problem: during Native class initialization, the Pointer class was loaded from JNI. When the pointer final field was initialized, it got the value from a not-yet-initialized Native class.
Turns out, this can be duplicated with pure Java code:
public class LoadTest {
public static final int VALUE;
static {
System.out.println("value=" + Secondary.VALUE);
VALUE = 1;
System.out.println("value=" + Secondary.VALUE);
}
}
class Secondary {
public static final int VALUE = LoadTest.VALUE;
}
When loaded, the class prints "value=0" twice, so final is final, just not the value I intended. Here, the problem is more apparent because the class dependency is clearly visible, which wasn't the case with the JNI initialization.
Maybe I'll call this antipattern something curiously obscure, like "Law of the Polygamist's Second Wife".