Skip to content

Instantly share code, notes, and snippets.

@routevegetable
Last active March 20, 2016 21:15
Show Gist options
  • Save routevegetable/657037b6ab0239bb5ac8 to your computer and use it in GitHub Desktop.
Save routevegetable/657037b6ab0239bb5ac8 to your computer and use it in GitHub Desktop.
Instantiate an object graph from a property file
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class PropsInstantiator {
private static Object getProperty(Object target, String propName) throws Exception {
for(Method m : target.getClass().getMethods()) {
String name = m.getName();
if(!name.startsWith("get") || m.getParameterTypes().length != 0)
continue;
name = name.substring(3);
if(name.equalsIgnoreCase(propName)) {
return m.invoke(target);
}
}
for(Field f : target.getClass().getFields()) {
String name = f.getName();
if(name.equalsIgnoreCase(propName)) {
return f.get(target);
}
}
return null;
}
private static abstract class SettableProperty {
public final String name;
public final Class<?> type;
public abstract void set(Object o) throws Exception;
public SettableProperty(String name, Class<?> type) {
this.name = name;
this.type = type;
}
public static SettableProperty getSettable(final Object target, String propName) {
for(Method m : target.getClass().getMethods()) {
String name = m.getName();
if(!name.startsWith("set") || m.getParameterTypes().length != 1)
continue;
name = name.substring(3);
if(name.equalsIgnoreCase(propName)) {
final Method myM = m;
return new SettableProperty(propName, m.getParameterTypes()[0]) {
public void set(Object o) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
myM.invoke(target, o);
}
};
}
}
for(Field f : target.getClass().getFields()) {
String name = f.getName();
if(name.equalsIgnoreCase(propName)) {
final Field myF = f;
return new SettableProperty(propName, f.getType()) {
public void set(Object o) throws IllegalArgumentException, IllegalAccessException {
myF.set(target, o);
}
};
}
}
return null;
}
}
private static Object parseEnum(Class<?> enumType, String str) {
if(!str.contains(".")) {
// Single enum
for(Object o : enumType.getEnumConstants()) {
Enum e = (Enum) o;
if(e.name().equals(str))
return e;
}
}
return null;
}
private static Object parseObjectReference(Object t, String path) throws Exception {
if(path.startsWith("@")) {
// Reference from root object
path = path.substring(1);
String[] parts = path.split("\\.");
for(int i = 0; i < parts.length && t != null; i++) {
t = getProperty(t, parts[i]);
}
return t;
} else if(path.startsWith("!")){
// New object
path = path.substring(1);
return Class.forName(path).newInstance();
}
return null;
}
public static void parse(InputStream is, Object target) throws Exception {
try(BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line = null;
while((line = br.readLine()) != null) {
if(line.isEmpty())
continue;
if(line.startsWith("#"))
continue;
String key = line.replaceFirst(" *=.*","");
String valueString = line.replaceFirst(".*= *","");
String[] keyParts = key.split("\\.");
Object t = target;
for(int i = 0; i < keyParts.length-1 && t != null; i++) {
t = getProperty(t, keyParts[i]);
}
SettableProperty s = SettableProperty.getSettable(t, keyParts[keyParts.length-1]);
Object refObj = parseObjectReference(target, valueString);
if(refObj != null) {
s.set(refObj);
} else if(s.type.isEnum()) {
s.set(parseEnum(s.type, valueString));
} else if(s.type == String.class) {
s.set(valueString);
} else if(s.type == Integer.class) {
s.set(Integer.parseInt(valueString));
} else if(s.type == Double.class) {
s.set(Double.parseDouble(valueString));
} else if(s.type == Float.class) {
s.set(Float.parseFloat(valueString));
}
}
}
}
}
class Test {
public static enum State {
RUNNING,
STOPPED;
}
private State state;
public Object child = null;
private String description = null;
public void setDescription(String description) {
this.description = description;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return this.state;
}
public static void main(String[] args) throws Exception {
Test t = new Test();
PropsInstantiator.parse(Test.class.getResourceAsStream("/test.properties"), t);
}
}
# Set a String setter
description=Hello There
# Set a field with a new object
child=!Test
# Set a String setter
child.description=I am the child thing
# Set an Enum setter
child.state=RUNNING
# Set an Enum setter with an object from elsewhere
state=@child.state
# Set a field with a new object
child.child=!java.lang.String
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment