5

Similar to this question, I need to access all the private fields of one instance of a POJO. The difference is that I don't know the specific name(s) of the field(s) I want ahead of time.

For example, if my POJO is:

public class Widget {
    private java.lang.String fizz;
    private java.lang.Boolean buzz;
    private com.me.myapp.Foo foo;
}

I'm looking for some way of inspecting a Widget instance (or the class itself) and seeing that it has those 3 fields/types, without knowing their names/types ahead of time.

Is this possible? If so, how? If not, why?

Update:

System.out.println("classToInspect = " + classToInspect.getName() + ", and fields are:\n");
for(Field f : allFields)
    System.out.println(f.getType());

Prints:

classToInspect = com.myorg.myapp.LoggerConfig, and fields are:

int
int
int
class java.lang.reflect.Constructor
class java.lang.Class
class java.lang.String
class java.security.ProtectionDomain
boolean
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
class java.lang.ref.SoftReference
int
int
class sun.reflect.generics.repository.ClassRepository
long
class [Ljava.io.ObjectStreamField;
class sun.reflect.ReflectionFactory
boolean
class [Ljava.lang.Object;
interface java.util.Map
class [Ljava.lang.annotation.Annotation;
interface java.util.Map
interface java.util.Map
class sun.reflect.annotation.AnnotationType

Please note: none of these fields are fields/properties/members of my actual LoggerConfig class; they must be provided/added through reflection or a part of the Object super class...

Community
  • 1
  • 1
  • Doesn't that question solve your issue? – Rohit Jain Jul 03 '13 at 15:04
  • Check out this question: http://stackoverflow.com/questions/1555658/is-it-possible-in-java-to-access-private-fields-via-reflection – Jan Dörrenhaus Jul 03 '13 at 15:05
  • And why do you _need_ to access them exactly? – fge Jul 03 '13 at 15:05
  • Also, this method will give you ALL declared fields, not just one with a given name: http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getDeclaredFields%28%29 – Jan Dörrenhaus Jul 03 '13 at 15:06
  • Also, remember that should you ever need to do this on a subclass, there could ve private fields on the superclass that you'll have to find too. – Fritz Jul 03 '13 at 15:08
  • Rohit - no that question specifically enumerates the field to extract through reflection. fge - I am building a component that searches for all the String fields of an object, scans them for instances of certain tokens, and replaces the tokens for certain values (sort of like a lightweight templating system). –  Jul 03 '13 at 15:13
  • What method did you use to get the list fields? – John B Jul 03 '13 at 15:24

4 Answers4

7

You can use the getDeclaredFields method of Class class to get all the fields that are declared in the class irrespective of its modifier. Using the getDeclaredFields method will provide you with an array of Field, which you can then iterate through, and call the getType method to get the types of the fields. The following code demonstrates the same:

class TestClass
{
    private String x;
    private int y;
    private boolean z;
}
public class Test
{
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException 
    {
        Class clazz = TestClass.class;
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) 
        {
            System.out.println("fieldName: "+field.getName()+", fieldType: "+field.getType());
        }
    }
}

The above code outputs:

fieldName: x, fieldType: class java.lang.String
fieldName: y, fieldType: int
fieldName: z, fieldType: boolean
Rahul Bobhate
  • 4,892
  • 3
  • 25
  • 48
5

use below to list all private fields

  List<Field> privateFields = new ArrayList<>();
    Field[] allFields = SomeClass.class.getDeclaredFields();
    for (Field field : allFields) {
        if (Modifier.isPrivate(field.getModifiers())) {
            privateFields.add(field);
            System.out.format("type is", field.getType());
        }
    }
M Sach
  • 33,416
  • 76
  • 221
  • 314
  • Thanks @M Sach - `getDeclaredFields()` does return all the fields, but when I print out their type via `getClass().getName()`, the field types print as `java.lang.reflect.Field`. **How can I get the underlying class type of the field itself?** Thanks again! –  Jul 03 '13 at 15:11
  • @TicketMonster try `field.getType()` – Esailija Jul 03 '13 at 15:13
  • @TicketMonster you're invoking those method on the `Field` class itself, that's why you're getting data related to `Field`. To get the type, use `getTipe()`. – Fritz Jul 03 '13 at 15:13
  • @TicketMonster see my update you can do it with System.out.format("type is", field.getType()); – M Sach Jul 03 '13 at 15:14
  • Thanks again (+1) - please see my update - `Field#getType()` is not working! –  Jul 03 '13 at 15:19
4

FYI, M Sach's answer works well for a single class but will not give private fields in a base class. I have implemented the following which will give all fields up the class heirarchy. This combined with that answer would be more versatile.

/**
 * Retrieves all fields (all access levels) from all classes up the class
 * hierarchy starting with {@code startClass} stopping with and not
 * including {@code exclusiveParent}.
 * 
 * Generally {@code Object.class} should be passed as
 * {@code exclusiveParent}.
 * 
 * @param startClass
 *            the class whose fields should be retrieved
 * @param exclusiveParent
 *            if not null, the base class of startClass whose fields should
 *            not be retrieved.
 * @return
 */
public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass, @Nullable Class<?> exclusiveParent) {
    List<Field> currentClassFields = newArrayList(startClass.getDeclaredFields());
    Class<?> parentClass = startClass.getSuperclass();

    if (parentClass != null && (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
        List<Field> parentClassFields = (List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
        currentClassFields.addAll(parentClassFields);
    }

    return currentClassFields;
}
John B
  • 32,493
  • 6
  • 77
  • 98
  • Thanks @John B (+1) - please see my update - `Field#getType()` is not working! –  Jul 03 '13 at 15:19
  • You should pass `Object.class` as the second argument of my method to prevent the fields in `Object` from being included in the list of fields. – John B Jul 03 '13 at 15:25
  • This should be the accepted answer; also I wanted to point out, for non-static inner classes, won't the results include a field that refers to the enclosing class instance? Just like how the `Constructor`s actually have the enclosing class instance as their first argument, even though it's syntactic sugared out of the code. – Andy Jul 11 '14 at 18:47
  • @Andork I am not sure. Please test and let us know. – John B Jul 14 '14 at 12:16
  • 1
    Just tested, yes, it does. Code: `public class A { private class B { } public static void main( String[ ] args ) { Class> cls = B.class; while( cls != null ) { for( Field field : cls.getDeclaredFields( ) ) { System.out.println( field ); } cls = cls.getSuperclass( ); } } } ` prints: `final A A$B.this$0` – Andy Jul 23 '14 at 03:23
1

Using reflection:

Widget widget = new Widget();
java.lang.reflect.Field[] fields = widget.getClass().getDeclaredFields();

You can use field.isAccessible() to check it's accessibility or even change it to public with field.setAccessible(true);

AntonioOtero
  • 1,759
  • 1
  • 14
  • 16