Saturday, July 20, 2013

Controlled reflection and template methods in java

This was in drafts for a long time and since then I have lost the original context. But I thought I'll make it compilable and let you, the reader, decide, whether you find any use for this.

Suppose you have a base class A. Suppose also that you need to instantiate two classes B and C, sub-classes of A, with the same configuration data. One straightforward way to achieve this in java is to use constructors:

ConfigData configData = setConfigData();
B b = new B(configData);
C c = new C(configData);

The question is: is there is a way to keep everything just in one method of the base class, governing setting the config data that would return an instance of a subclass of A (B or C)?

Yes, there is! One way to set this is to implement a ctor in the base class A.

Another method is to use "templated" reflection. By "templated" I here refer to Java generics. In order to make sure we get the proper class instances, we should limit the accepted classes with <T extends A>:

public class A {
// declaration updated thanks to Pitko's comment below
public static <t extends A> t configureA(Class<a> ATemplateClass) {
t a;
 ConfigData configData = setConfigData();
 a = ATemplateClass.getConstructor(ConfigData.class).newInstance(configData);
 return a;
    }

private static ConfigData setConfigData() {
        ConfigData configData = new ConfigData("configParam1Value");
 return configData;
    }
}

public class ConfigData {
public String configParam1;

public ConfigData(String _configParam1) {
configParam1 = _configParam1;
}

/* (non-Javadoc)
 * @see java.lang.Object#toString()
 */
@Override
public String toString() {
   return "ConfigData [configParam1=" + configParam1 + "]";
}
}
The child classes will look alike (in practise they will have differrent implementation logic), illustrating with just B subclass:

public class B extends A {
ConfigData configData;

public B(ConfigData _configData) {
this.configData = _configData; 
}

/**
* @return the configData
*/
public ConfigData getConfigData() {
   return configData;
}
}

Now we can say:

B b = A.configureA(B.class);
C c = A.configureA(C.class);
  
System.out.println("Class B:" + b.getConfigData());
System.out.println("Class C:" + c.getConfigData()); 

// which outputs:
Class B:ConfigData [configParam1=configParam1Value]
Class C:ConfigData [configParam1=configParam1Value]

This post illustrates the usage of reflection and generics in java. We were able to access child classes in the base class using "controlled" reflection, that is we allowed only subclasses of the base class to be passed in the reflecitve method. We use generics to return proper subclass instances from the base class.