views:

86

answers:

2

How is it possible to know whether a class has been initialized?

Class cl = Class.forName("com.example.MyClass", false, getClass().getClassLoader());
// the false argument above indicates that the class should not be initialized
// but how can I check whether it already was?
cl.isInitialized(); // this does not exist, how can I know instead?

About why I want to know that:

On a client's project, we have an ugly class(*) with lots of static members which I want to test. For the test to be predictable, the static members must have their default values, which are set on initializing. If the JUnit testing starts a new JVM for each test class, this is not a problem: the class is freshly loaded on each execution. But when I execute the tests in Eclipse along with others, the same JVM is used for several tests and the class is not freshly loaded and the members don't have their default values anymore. I want to be able to decide, whether the test makes sense (because the class will be freshly loaded) or if I should just return because the test makes not sense if the static members have been modified.

(*) refactoring is scheduled, but not just for right now

Simplified version of the class

public class Settings {
  public static Properties props;
  static{
    props.setProperty("key1", "val1");
    props.setProperty("key2", "val2");
  }
}  

And the test class

public class SettingsTest extends TestCase {
  public void testDefauts() throws Exception {
    Class cl = Class.forName("Settings", false, getClass().getClassLoader());
    if(cl.isInitialized){ // doesn't exist
      // Cannot test default values, because class was already initialized
      return;
    }

    Properties props = Settings.props; // Settings is initialized here
    assertEquals("val1", props.getProperty("key1"));
    assertEquals("val2", props.getProperty("key2"));
  }
}
A: 

Class.forName() will initialise it, but you can call it in a way that doesn't. In any case, you are in a position to know whether it has been initialised.

Edit:

I misunderstood the problem there. I thought you wanted to know whether it had not been initialised before. If you're in an ugly mood anyways, you could set some other class' static field in the static block of the class in question, like this:

public class UglyClass {
    static {
        AnotherUglyClass.uglyClassInitialized = true;
    }
}

public class AnotherUglyClass {
    public static boolean uglyClassInitialized = false;
}

Did I mention it's ugly? :)

fhd
If the class is already initialized, calling Class.forName(String,boolean,ClassLoader) will not un- or re-initialize it.
Philipp
Okay, I misunderstood that. I edited my answer and suggested a different solution.
fhd
+1  A: 

A class's static initializers (which is what the static { ... } block is called) are executed the first time a class is loaded by the class loader. They are guaranteed to be called just once, and in a thread-safe manner before any other thread is allowed to access the class.

I'm not sure that the unit test you have has much value. You are testing the values placed into the Properties object by the static {...} block. Isn't it straight-forward to see what the default/initial values are, just based on the code in the Settings class itself? In other words, you are testing logic that cannot fail, unless someone changes the default values.

I think you are far better off just removing the nastiness of the static blocks, static Properties object which (it sounds like) other threads/classes are modifying, etc; rather than spending lots of time trying to find a decent way to unit test ugly code.

matt b
About your first paragraph: loading and initialization are two steps not necessarily done at the same time. I'm precisely speaking of loaded classes which are not initialized. The point of the test, was actually to prevent regressions while refactoring... And yes, it will be refactored.
Philipp