jeudi 17 août 2023

Get static field through reflection without triggering initialization?

We have a WAR application which uses a third-party library that creates a threadpool with a running thread as a static field of one of its internal classes. When we undeploy the WAR, this thread continues running. To work around this, I want to run some code during undeployment which uses reflection to access the private static field and shut down the thread pool.

The threadpool is created in a static initializer for the class. It's possible the class in question hasn't been loaded or initialized when our shutdown code runs, and I don't want the shutdown code to initialize the class just to shut it down again if I can avoid that.

I can use the three-argument form of Class.forName() to get the class without initializing it. However, after getting the Field that I want, getting the value of the field still triggers the class to be initialized. I'm looking for a way to avoid that.

Here is some example code:

package scratch;
public class A {
    private static final String field;
    static {
        System.out.println("A initializing");
        field = "I'm initialized!";
    }
}

package scratch;
public class B {
    public static void main(String[] args) {
        // var a = new A();
        try {
            System.out.println("B starting");
            var clazz = Class.forName("scratch.A", false, B.class.getClassLoader());
            System.out.println("B got class");
            var field = clazz.getDeclaredField("field");
            System.out.println("B got field");
            field.setAccessible(true);
            System.out.println("B set accessible");
            var value = field.get(null);
            System.out.println("B got value '" + value + "'");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

Running this code produces this output:

B starting
B got class
B got field
B set accessible
A initializing
B got value 'I'm initialized!'

The call to Field.get() triggers initialization of the class.

I just want to avoid initializing the class (if it's not already initialized) in the process of accessing this field to shut it down. Is there any way to avoid fetching the class if it's not already loaded? Or to test whether it's initialized before fetching the field? Or to fetch the value of the field without triggering initialization?





Aucun commentaire:

Enregistrer un commentaire