package org.jboss.tools.smooks.launch;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JavaGraphBuilder {
public <T> T buildGraph(Class<T> messageType) {
try {
return buildObject(messageType);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("Unable to construct an instance of '" + messageType.getName() + "'", e);
}
}
@SuppressWarnings("unchecked")
private <T> T buildObject(Class<T> objectType) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
if(String.class.isAssignableFrom(objectType)) {
return objectType.cast("x");
} else if(Number.class.isAssignableFrom(objectType)) {
return objectType.getConstructor(String.class).newInstance("1");
} else if(objectType.isPrimitive()) {
return (T) primitiveToObjectMap.get(objectType);
} else if(objectType == Object.class) {
// don't construct raw Object types... leave them and just return null...
return null;
} else if(objectType.isEnum()) {
return (T) EnumSet.allOf((Class<Enum>)objectType).iterator().next();
}
T messageInstance = objectType.newInstance();
// populate all the fields...
Method[] methods = objectType.getMethods();
for(Method method : methods) {
if(method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
Class<?> propertyType = method.getParameterTypes()[0];
Object propertyInstance = null;
if(Collection.class.isAssignableFrom(propertyType)) {
propertyInstance = buildCollection(method, propertyType);
} else if(propertyType.isArray()) {
propertyInstance = buildArray(method, propertyType);
} else {
propertyInstance = buildObject(propertyType);
}
if(propertyInstance != null) {
method.invoke(messageInstance, propertyInstance);
}
}
}
return messageInstance;
}
private Object buildArray(Method method, Class<?> propertyType) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Class<?> arrayType = propertyType.getComponentType();
Object[] arrayObj = (Object[]) Array.newInstance(arrayType, 1);
Array.set(arrayObj, 0, buildObject(arrayType));
return arrayObj;
}
private Object buildCollection(Method method, Class<?> propertyType) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Type genericType = method.getGenericParameterTypes()[0];
if(genericType instanceof ParameterizedType) {
ParameterizedType genericTypeClass = (ParameterizedType) genericType;
Collection collection = null;
if(!propertyType.isInterface()) {
// It's a concrete Collection type... just create an instance...
collection = (Collection) propertyType.newInstance();
}else if(List.class.isAssignableFrom(propertyType)) {
collection = new ArrayList();
} else if(Set.class.isAssignableFrom(propertyType)) {
collection = new LinkedHashSet();
}
if(collection != null) {
collection.add(buildObject((Class<Object>) genericTypeClass.getActualTypeArguments()[0]));
return collection;
}
}
return null;
}
private static final Map<Class, Object> primitiveToObjectMap;
static {
primitiveToObjectMap = new HashMap<Class, Object>();
primitiveToObjectMap.put(int.class, 1);
primitiveToObjectMap.put(long.class, 1L);
primitiveToObjectMap.put(boolean.class, true);
primitiveToObjectMap.put(float.class, 1f);
primitiveToObjectMap.put(double.class, 1d);
primitiveToObjectMap.put(char.class, '1');
primitiveToObjectMap.put(byte.class, Byte.parseByte("1"));
primitiveToObjectMap.put(short.class, 1);
}
}