Static block fails to execute for self-registering object in Java

java

Solution

You can read about class loading in this blog post. The point is that a class won't be loaded until it is referenced. And the static blocks of a class won't be executed until the class is loaded. The rules are

- an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.

- an static method of Class is invoked.

- an static field of Class is assigned.

- an static field of class is used which is not a constant variable.

- if Class is a top level class and an assert statement lexically nested within class is executed.

A solution is to either instantiate `B` or call a no-op static method (or any of the above).

public class B {
    static {
        A.register("Foo", new Factory() {
            public Object create() {
                return new B();
            }
        });
    }

    public void static noOp() {}

    public B() {
        // Create a new instance of class B
    }
}

...

B.noOp();

The Oracle JVM spec states this here.

Problem

This is a bit of a tricky one to explain, but let's say I have two classes `A` and `B`. `A` contains a `static` list of factory objects that are registered by each object that provides such a factor. In this example `B` is such a class and provides an imaginary `Factory` implementation. Class A: ``` public class A { protected static Map<String, Factory> registered = new HashMap<String, Factory>(); protected static register(String name, Factory factory) { registered.put(name, factory); } public A() { // Do something with the factories we've registered } } ``` Class B: ``` public class B { static { A.register("Foo", new Factory() { public Object create() { return new B(); } }); } public B() { // Create a new instance of class B } } ``` In my program for some strange reason the static block within `B` is never called, so when I start interacting with `A` no factories have been registered so it can't do what it needs to do. If I move the creation of each `Factory` into `A` directly there is no problem of course. I'm working under the assumption that because there are no clear references to `B` from any class that the compiler isn't recognising there's a link between `A` and `B` so doesn't bother with `B` at all. Is there anything I can do to work around this? I'd hoped to avoid adding each new factory into `A` directly as it makes maintenance more difficult than having new factories simply register themselves, but clearly having none of them work at all is even worse; still, I'd like to somehow get it to work as intended if I can. In case it's relevant, the particular JVM I'm working with is the Android JVM, could this be a side-effect of some optimisation that that that JVM is using?

Original source