Search code examples
javareflectiondynamic-class-loaders

Is it possible to reinitialize static mutable fields in a class?


I'm trying to automate the testing process for customly written programs designed to solve competitive programming challenges. Below is a dummy sample implementation of Solution:

public class Solution {
    private static String dummyField = "initial";


    public static int initialize(InputStream in) {
        //competitive programmer custom code
        System.out.println(dummyField);
        dummyField = "changed";
        return subCaseCount;
    }

    public void processSingleSubCase(InputStream in) {
        //competitive programmer custom code
    }
}

Prewritten test code for solution regardless of its implementation:

public void testSolution() throws FileNotFoundException {
        for(File testResource : testResources) {
            InputStream in = new FileInputStream(testResource);
            int subCaseCount = Foo.initialize(in);
            for (int subCase = 0; subCase < subCaseCount; subCase++) {
                new Foo().processSingleSubCase(in);
            }

            //magic call to re-init all static fields without knowing their number/names in advance goes here
        }

        //console current output:
        //initial
        //changed
        //changed
        //...

        //desired:
        //initial
        //initial
        //initial
        //....
}

The static fields can be mutable, so caching the initial values and mapping them to field names using reflection as a first setup, then reassigning them in between iterations won't do.

I did manage to come up with a working solution which basically reloads the class using a different class loader in between iterations, it did work but was slow: it took about 50 seconds just to reload classes 300 times (test resources are auto generated and I'd like to have the flexibility to auto generate as many as tolerable).

Is there a faster alternative?


Solution

  • My two thoughts for how to do this are:

    1. Use instances rather than statics, since that way the new instance for each test is fresh.

    2. If you need (or want) to stick with statics: Prior to the first test, cache the static values, then reassign them from the cache between tests. If the static values are object references referring to mutable objects, you'll need to make deep copies.