43

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 these objects, but I don't know the objects' class.

Is there a way to do this via Reflecion or somehow else?

1

5 Answers 5

66

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 :)

Sign up to request clarification or add additional context in comments.

6 Comments

"Assumptions...reflection available (not android)" Um according to whom? The reflect package has been available in Android since API lvl 1 developer.android.com/reference/java/lang/reflect/…
Apparently I was mistaken on that small point a year ago. Edited. The main point remains, There are many Java based platforms on which reflection is not available for one reason or another.
@Charlie: But how to deal with the Objects coming from SQL queries ran in Hibernate. If you have multiple methods, you have to create that many Class prototypes for each result, right? Is there a easier way for that??
This solution is true for only public Fields.
plz use getDeclaredFields for acessing declaredFields only for private fields acessibility
|
6

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

3 Comments

Generics is not the case, cause I have no access to the method code.
The example I posted should help then. It makes even private and final fields accessible for runtime inspection.
how do I get the value "some value" instead of "[C@1b67f74"?
3

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

3 Comments

Admittedly, if you're using groovy, the last time I used it (~1.7 era) you could just do b.stuff and groovy would do all the reflection and breaking of private for you... (with the caviat that it also does syntatic sugar for java bean methods getX). :)
@Charlie: yes, b.stuff is enough for this in groovy.
This works great and the big key for my use case was using setAccessible; this is coming from a weak Java background, but stronger in other languages. I moved some reflection logic and things started failing when I could no longer access the values until adding setAccessible.
1
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"));

Comments

-1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.