Hi Oleksandr
Thanks for your reply. It is not entirely impossible as highlighted in 2 articles:
http://www.ibm.com/developerworks/ja...-cwt11085.html
http://www.artima.com/weblogs/viewpo...?thread=208860
This require some Java 1.5 code (but it could be made backward compatible by some tools). In any case, I'd think that Spring could either come up with a spring-core-jdk15 using these technologies or define some kind of Annotation that would make the BeanWrapper able to find out more about the PropertyType (why not using getPropertyValue().getClass() as the first attempt).
For instance in the enclosed code that shows it is possible to find out the generic type of a property.
Class net.objectlab.springtest.GenericTest details:
intSuper2 is of parameterized type
net.objectlab.springtest.GenericTest$Super1
using types (java.lang.Integer)
Class net.objectlab.springtest.GenericTest$Super1 details:
id is of type java.lang.Object
Not a 'clean' solution of course, but it shows that it may not be impossible I'd think. Especially if the developers were to adhere to a convention of some sort...
My £0.02 suggestion,
Benoit
Code:
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.binding.form.FormModel;
import org.springframework.richclient.form.FormModelHelper;
public class GenericTest {
private Super1<Integer> intSuper2;
public Super1<Integer> getIntSuper2() {
return intSuper2;
}
public void setIntSuper2(Super1<Integer> intSuper2) {
this.intSuper2 = intSuper2;
}
public static void main(String[] a) {
try {
analyze("", GenericTest.class);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static HashSet<String> s_processed = new HashSet<String>();
private static void describe(String lead, Field field) {
// get base and generic types, check kind
Class<?> btype = field.getType();
Type gtype = field.getGenericType();
if (gtype instanceof ParameterizedType) {
// list basic parameterized type information
ParameterizedType ptype = (ParameterizedType) gtype;
System.out.println(lead + field.getName() + " is of parameterized type");
System.out.println(lead + ' ' + btype.getName());
// print list of actual types for parameters
System.out.print(lead + " using types (");
Type[] actuals = ptype.getActualTypeArguments();
for (int i = 0; i < actuals.length; i++) {
if (i > 0) {
System.out.print(" ");
}
Type actual = actuals[i];
if (actual instanceof Class) {
System.out.print(((Class) actual).getName());
} else {
System.out.print(actuals[i]);
}
}
System.out.println(")");
// analyze all parameter type classes
for (int i = 0; i < actuals.length; i++) {
Type actual = actuals[i];
if (actual instanceof Class) {
analyze(lead, (Class) actual);
}
}
} else if (gtype instanceof GenericArrayType) {
// list array type and use component type
System.out.println(lead + field.getName() + " is array type " + gtype);
gtype = ((GenericArrayType) gtype).getGenericComponentType();
} else {
// just list basic information
System.out.println(lead + field.getName() + " is of type " + btype.getName());
}
// analyze the base type of this field
analyze(lead, btype);
}
private static void analyze(String lead, Class<?> clas) {
// substitute component type in case of an array
if (clas.isArray()) {
clas = clas.getComponentType();
}
// make sure class should be expanded
String name = clas.getName();
if (!clas.isPrimitive() && !clas.isInterface() && !name.startsWith("java.lang.") && !s_processed.contains(name)) {
// print introduction for class
s_processed.add(name);
System.out.println(lead + "Class " + clas.getName() + " details:");
// process each field of class
String indent = lead + ' ';
Field[] fields = clas.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (!Modifier.isStatic(field.getModifiers())) {
describe(indent, field);
}
}
}
}