Say, I have a method that returns a custom List
with some objects. They are returned as Object
to me. I need to get value of a certain field from t
If you know what class the field is on you can access it using reflection. This example (it's in Groovy but the method calls are identical) gets a Field object for the class Foo and gets its value for the object b
. It shows that you don't have to care about the exact concrete class of the object, what matters is that you know the class the field is on and that that class is either the concrete class or a superclass of the object.
groovy:000> class Foo { def stuff = "asdf"}
===> true
groovy:000> class Bar extends Foo {}
===> true
groovy:000> b = new Bar()
===> Bar@1f2be27
groovy:000> f = Foo.class.getDeclaredField('stuff')
===> private java.lang.Object Foo.stuff
groovy:000> f.getClass()
===> class java.lang.reflect.Field
groovy:000> f.setAccessible(true)
===> null
groovy:000> f.get(b)
===> asdf
Assuming a simple case, where your field is public
:
List list; // from your method
for(Object x : list) {
Class<?> clazz = x.getClass();
Field field = clazz.getField("fieldName"); //Note, this can throw an exception if the field doesn't exist.
Object fieldValue = field.get(x);
}
But this is pretty ugly, and I left out all of the try-catches, and makes a number of assumptions (public field, reflection available, nice security manager).
If you can change your method to return a List<Foo>
, this becomes very easy because the iterator then can give you type information:
List<Foo> list; //From your method
for(Foo foo:list) {
Object fieldValue = foo.fieldName;
}
Or if you're consuming a Java 1.4 interface where generics aren't available, but you know the type of the objects that should be in the list...
List list;
for(Object x: list) {
if( x instanceof Foo) {
Object fieldValue = ((Foo)x).fieldName;
}
}
No reflection needed :)
I strongly recommend using Java generics to specify what type of object is in that List, ie. List<Car>
. If you have Cars and Trucks you can use a common superclass/interface like this List<Vehicle>
.
However, you can use Spring's ReflectionUtils to make fields accessible, even if they are private like the below runnable example:
List<Object> list = new ArrayList<Object>();
list.add("some value");
list.add(3);
for(Object obj : list)
{
Class<?> clazz = obj.getClass();
Field field = org.springframework.util.ReflectionUtils.findField(clazz, "value");
org.springframework.util.ReflectionUtils.makeAccessible(field);
System.out.println("value=" + field.get(obj));
}
Running this has an output of:
value=[C@1b67f74
value=3
There is one more way, i got the same situation in my project. i solved this way
List<Object[]> list = HQL.list();
In above hibernate query language i know at which place what are my objects so what i did is :
for(Object[] obj : list){
String val = String.valueOf(obj[1]);
int code =Integer.parseint(String.valueof(obj[0]));
}
this way you can get the mixed objects with ease, but you should know in advance at which place what value you are getting or you can just check by printing the values to know. sorry for the bad english I hope this help
public abstract class Refl {
/** Use: Refl.<TargetClass>get(myObject,"x.y[0].z"); */
public static<T> T get(Object obj, String fieldPath) {
return (T) getValue(obj, fieldPath);
}
public static Object getValue(Object obj, String fieldPath) {
String[] fieldNames = fieldPath.split("[\\.\\[\\]]");
String success = "";
Object res = obj;
for (String fieldName : fieldNames) {
if (fieldName.isEmpty()) continue;
int index = toIndex(fieldName);
if (index >= 0) {
try {
res = ((Object[])res)[index];
} catch (ClassCastException cce) {
throw new RuntimeException("cannot cast "+res.getClass()+" object "+res+" to array, path:"+success, cce);
} catch (IndexOutOfBoundsException iobe) {
throw new RuntimeException("bad index "+index+", array size "+((Object[])res).length +" object "+res +", path:"+success, iobe);
}
} else {
Field field = getField(res.getClass(), fieldName);
field.setAccessible(true);
try {
res = field.get(res);
} catch (Exception ee) {
throw new RuntimeException("cannot get value of ["+fieldName+"] from "+res.getClass()+" object "+res +", path:"+success, ee);
}
}
success += fieldName + ".";
}
return res;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName + "' not found in class " + clazz);
}
private static int toIndex(String s) {
int res = -1;
if (s != null && s.length() > 0 && Character.isDigit(s.charAt(0))) {
try {
res = Integer.parseInt(s);
if (res < 0) {
res = -1;
}
} catch (Throwable t) {
res = -1;
}
}
return res;
}
}
It supports fetching fields and array items, e.g.:
System.out.println(""+Refl.getValue(b,"x.q[0].z.y"));
there is no difference between dots and braces, they are just delimiters, and empty field names are ignored:
System.out.println(""+Refl.getValue(b,"x.q[0].z.y[value]"));
System.out.println(""+Refl.getValue(b,"x.q.1.y.z.value"));
System.out.println(""+Refl.getValue(b,"x[q.1]y]z[value"));