How to access a field's value in an object using reflection

kentcdodds picture kentcdodds · Oct 8, 2012 · Viewed 34.1k times · Source

My Question: How to overcome an IllegalAccessException to access the value of an object's field using reflection.

Expansion: I'm trying to learn about reflection to make some of my projects more generic. I'm running into an IllegalAccessException when trying to call field.getValue(object) to get the value of that field in that object. I can get the name and type just fine.

If I change the declaration from private to public then this works fine. But in an effort to follow the "rules" of encapsulation I don't want to do this. Any help would be greatly appreciated! Thanks!

My Code:

package main;

import java.lang.reflect.Field;

public class Tester {

  public static void main(String args[]) throws Exception {
    new Tester().reflectionTest();
  }

  public void reflectionTest() throws Exception {
    Person person = new Person("John Doe", "555-123-4567", "Rover");
    Field[] fields = person.getClass().getDeclaredFields();
    for (Field field : fields) {
      System.out.println("Field Name: " + field.getName());
      System.out.println("Field Type: " + field.getType());
      System.out.println("Field Value: " + field.get(person));
      //The line above throws: Exception in thread "main" java.lang.IllegalAccessException: Class main.Tester can not access a member of class main.Tester$Person with modifiers "private final"
    }
  }

  public class Person {

    private final String name;
    private final String phoneNumber;
    private final String dogsName;

    public Person(String name, String phoneNumber, String dogsName) {
      this.name = name;
      this.phoneNumber = phoneNumber;
      this.dogsName = dogsName;
    }
  }
}

The Output:

run:
Field Name: name
Field Type: class java.lang.String
Exception in thread "main" java.lang.IllegalAccessException: Class main.Tester can not access a member of class main.Tester$Person with modifiers "private final"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
    at java.lang.reflect.Field.doSecurityCheck(Field.java:983)
    at java.lang.reflect.Field.getFieldAccessor(Field.java:927)
    at java.lang.reflect.Field.get(Field.java:372)
    at main.Tester.reflectionTest(Tester.java:17)
    at main.Tester.main(Tester.java:8)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)

Answer

Michael Berry picture Michael Berry · Oct 8, 2012

Before you get a private field, you need to call setAccessible(true); on the corresponding field:

for (Field field : fields) {
    field.setAccessible(true); // Additional line
    System.out.println("Field Name: " + field.getName());
    System.out.println("Field Type: " + field.getType());
    System.out.println("Field Value: " + field.get(person));
}