How can I access an inherited protected field from an object by reflection?
-
2The question would be better if you stated what you tried (exactly) and what happened (exactly). – Tom Hawtin - tackline Apr 09 '09 at 18:41
11 Answers
Two issues you may be having issues with - the field might not be accessible normally (private), and it's not in the class you are looking at, but somewhere up the hierarchy.
Something like this would work even with those issues:
public class SomeExample {
public static void main(String[] args) throws Exception{
Object myObj = new SomeDerivedClass(1234);
Class myClass = myObj.getClass();
Field myField = getField(myClass, "value");
myField.setAccessible(true); //required if field is not normally accessible
System.out.println("value: " + myField.get(myObj));
}
private static Field getField(Class clazz, String fieldName)
throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
}
class SomeBaseClass {
private Integer value;
SomeBaseClass(Integer value) {
this.value = value;
}
}
class SomeDerivedClass extends SomeBaseClass {
SomeDerivedClass(Integer value) {
super(value);
}
}

- 32,208
- 39
- 178
- 361

- 6,688
- 2
- 27
- 23
-
6If there is a security manager, this would fail. You need to wrap up the call to setAccessible and getDeclaredField in a PriviledgedAction, and run it through java.security.AccessController.doPrivileged(...) – Varkhan Apr 09 '09 at 18:32
-
2
-
This does not work on Android :( My class tree looks like this A->B->C and inside C I cannot get the value of a protected field declared in A. Note all three classes are in different packages. Any ideas how to get around this? – Moonwalker Feb 19 '15 at 15:29
Use FieldUtils.writeField(object, "fieldname", value, true)
or readField(object, "fieldname", true)
from Apache Commons lang3.

- 16,697
- 8
- 89
- 72
Use reflection to access the members of the class instance, make them accessible and set their respective values. Of course you'd have to know the name of each member you want to change, but I guess that won't be a problem.
public class ReflectionUtil {
public static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers()))
{
field.setAccessible(true);
}
}
}
public class Application {
public static void main(String[] args) throws Exception {
KalaGameState obj = new KalaGameState();
Field field = ReflectionUtil.getField(obj.getClass(), 'turn');
ReflectionUtil.makeAccessible(field);
field.setInt(obj, 666);
System.out.println("turn is " + field.get(obj));
}
}

- 31,198
- 5
- 66
- 97
If using Spring, ReflectionTestUtils provides some handy tools that help out here with minimal effort.
For example, to get a protected field value that is known to be an int
:
int theIntValue = (int)ReflectionTestUtils.getField(theClass, "theProtectedIntField");
Or alternatively to set this field's value:
ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue);

- 37,270
- 24
- 156
- 208
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);

- 32,610
- 9
- 70
- 97
-
1This may not work if there is a security manager that blocks the relevant permission. – Miguel Ping Apr 09 '09 at 18:01
-
-
Thanx for try, but as Javadoc (and I tried it) it Returns a Field object that reflects the specified declared field of the class or interface represented by this Class object. it doesn't go through super classes. – Moro Apr 09 '09 at 18:09
-
Sorry,it wasn't clear that you didn't new in which class the field was declared – Maurice Perry Apr 09 '09 at 19:00
I didn't want to drag in more libraries so I made a pure one that worked for me. It is an extension of one of the methods from jweyrich:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
public abstract class POJOFiller {
static final Random random = new Random();
public static void fillObject(Object ob) {
Class<? extends Object> clazz = ob.getClass();
do {
Field[] fields = clazz.getDeclaredFields();
fillForFields(ob, fields);
if (clazz.getSuperclass() == null) {
return;
}
clazz = clazz.getSuperclass();
} while (true);
}
private static void fillForFields(Object ob, Field[] fields) {
for (Field field : fields) {
field.setAccessible(true);
if(Modifier.isFinal(field.getModifiers())) {
continue;
}
try {
field.set(ob, generateRandomValue(field.getType()));
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
static Object generateRandomValue(Class<?> fieldType) {
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis());
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else if (fieldType.equals(Integer.TYPE)) {
return random.nextInt();
} else if (fieldType.equals(Long.TYPE)) {
return random.nextInt();
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if(fieldType.equals(Integer[].class)) {
return new Integer[] {random.nextInt(), random.nextInt()};
}
else {
throw new IllegalArgumentException("Cannot generate for " + fieldType);
}
}
}

- 8,333
- 4
- 19
- 25
If you are just getting the protected field
Field protectedfield = Myclazz.class.getSuperclass().getDeclaredField("num");
If you are using Eclipse Ctrl + Space will bring up a list of methods when you type a "." after the object

- 11
- 3
use this utility:
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Stream;
import static java.lang.String.format;
public final class ReflectionUtils {
private ReflectionUtils() { }
private static final String GETTER_PREFIX = "get";
private static final String SETTER_PREFIX = "set";
/**
* Get name of getter
*
* @param fieldName fieldName
* @return getter name
*/
public static String getterByFieldName(String fieldName) {
if (isStringNullOrEmpty(fieldName))
return null;
return convertFieldByAddingPrefix(fieldName, GETTER_PREFIX);
}
/**
* Get name of setter
*
* @param fieldName fieldName
* @return setter name
*/
public static String setterByFieldName(String fieldName) {
if (isStringNullOrEmpty(fieldName))
return null;
return convertFieldByAddingPrefix(fieldName, SETTER_PREFIX);
}
/**
* Get the contents of the field with any access modifier
*
* @param obj obj
* @param fieldName fieldName
* @return content of field
*/
public static Object getFieldContent(Object obj, String fieldName) {
if (!isValidParams(obj, fieldName))
return null;
try {
Field declaredField = getFieldAccessible(obj, fieldName);
return declaredField.get(obj);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot get field content for field name: " + fieldName, e);
}
}
/**
* @param clazz clazz
* @param fieldName fieldName
* @return content static field
*/
public static Object getStaticFieldContent(final Class<?> clazz, final String fieldName) {
try {
Field field = getFieldWithCheck(clazz, fieldName);
field.setAccessible(true);
return field.get(clazz);
} catch (Exception e) {
String exceptionMsg = format("Cannot find or get static field: '%s' from class: '%s'", fieldName, clazz);
throw new RuntimeException(exceptionMsg, e);
}
}
/**
* Set the contents to the field with any access modifier
*
* @param obj obj
* @param fieldName fieldName
* @param value value
*/
public static void setFieldContent(Object obj, String fieldName, Object value) {
if (!isValidParams(obj, fieldName))
return;
try {
Field declaredField = getFieldAccessible(obj, fieldName);
declaredField.set(obj, value);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot set field content for field name: " + fieldName, e);
}
}
/**
* Call a method with any access modifier
*
* @param obj obj
* @param methodName methodName
* @return result of method
*/
public static Object callMethod(Object obj, String methodName) {
if (!isValidParams(obj, methodName))
return null;
try {
Method method = obj.getClass().getMethod(methodName);
method.setAccessible(true);
return method.invoke(obj);
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new IllegalArgumentException("Cannot invoke method name: " + methodName, e);
}
}
/**
* Get all fields even from parent
*
* @param clazz clazz
* @return array of fields
*/
public static Field[] getAllFields(Class<?> clazz) {
if (clazz == null) return null;
List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
if (clazz.getSuperclass() != null) {
// danger! Recursion
fields.addAll(Arrays.asList(getAllFields(clazz.getSuperclass())));
}
return fields.toArray(new Field[] {});
}
/**
* Get the Field from Object even from parent
*
* @param obj obj
* @param fieldName fieldName
* @return {@code Optional}
*/
public static Optional<Field> getField(Object obj, String fieldName) {
if (!isValidParams(obj, fieldName))
return Optional.empty();
Class<?> clazz = obj.getClass();
return getField(clazz, fieldName);
}
/**
* Get the Field from Class even from parent
*
* @param clazz clazz
* @param fieldName fieldName
* @return {@code Optional}
*/
public static Optional<Field> getField(Class<?> clazz, String fieldName) {
if (!isValidParams(clazz, fieldName))
return Optional.empty();
Field[] fields = getAllFields(clazz);
return Stream.of(fields)
.filter(x -> x.getName().equals(fieldName))
.findFirst();
}
/**
* @param clazz clazz
* @param fieldName fieldName
* @return Class
*/
public static Class<?> getFieldType(Class<?> clazz, String fieldName) {
return getFieldWithCheck(clazz, fieldName).getType();
}
/**
* @param clazz clazz
* @param fieldName fieldName
* @return Field
*/
public static Field getFieldWithCheck(Class<?> clazz, String fieldName) {
return ReflectionUtils.getField(clazz, fieldName)
.orElseThrow(() -> {
String msg = String.format("Cannot find field name: '%s' from class: '%s'", fieldName, clazz);
return new IllegalArgumentException(msg);
});
}
/**
* Get the field values with the types already listed according to the field type
*
* @param clazz clazz
* @param fieldName fieldName
* @param fieldValue fieldValue
* @return value cast to specific field type
*/
public static Object castFieldValueByClass(Class<?> clazz, String fieldName, Object fieldValue) {
Field field = getField(clazz, fieldName)
.orElseThrow(() -> new IllegalArgumentException(String.format("Cannot find field by name: '%s'", fieldName)));
Class<?> fieldType = field.getType();
return castFieldValueByType(fieldType, fieldValue);
}
/**
* @param fieldType fieldType
* @param fieldValue fieldValue
* @return casted value
*/
public static Object castFieldValueByType(Class<?> fieldType, Object fieldValue) {
if (fieldType.isAssignableFrom(Boolean.class)) {
if (fieldValue instanceof String) {
return convertStringToBoolean((String) fieldValue);
}
if (fieldValue instanceof Number) {
return !(fieldValue).equals(0);
}
return fieldValue;
}
else if (fieldType.isAssignableFrom(Double.class)) {
if (fieldValue instanceof String) {
return Double.valueOf((String)fieldValue);
}
return ((Number) fieldValue).doubleValue();
}
else if (fieldType.isAssignableFrom(Long.class)) {
if (fieldValue instanceof String) {
return Long.valueOf((String)fieldValue);
}
return ((Number) fieldValue).longValue();
}
else if (fieldType.isAssignableFrom(Float.class)) {
if (fieldValue instanceof String) {
return Float.valueOf((String)fieldValue);
}
return ((Number) fieldValue).floatValue();
}
else if (fieldType.isAssignableFrom(Integer.class)) {
if (fieldValue instanceof String) {
return Integer.valueOf((String)fieldValue);
}
return ((Number) fieldValue).intValue();
}
else if (fieldType.isAssignableFrom(Short.class)) {
if (fieldValue instanceof String) {
return Short.valueOf((String)fieldValue);
}
return ((Number) fieldValue).shortValue();
}
return fieldValue;
}
private static boolean convertStringToBoolean(String s) {
String trim = s.trim();
return !trim.equals("") && !trim.equals("0") && !trim.toLowerCase().equals("false");
}
private static boolean isValidParams(Object obj, String param) {
return (obj != null && !isStringNullOrEmpty(param));
}
private static boolean isStringNullOrEmpty(String fieldName) {
return fieldName == null || fieldName.trim().length() == 0;
}
private static Field getFieldAccessible(Object obj, String fieldName) {
Optional<Field> optionalField = getField(obj, fieldName);
return optionalField
.map(el -> {
el.setAccessible(true);
return el;
})
.orElseThrow(() -> new IllegalArgumentException("Cannot find field name: " + fieldName));
}
private static String convertFieldByAddingPrefix(String fieldName, String prefix) {
return prefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
}
}

- 868
- 1
- 8
- 26
A generic utility method to run any getter in this or any superclass.
Adapted from Marius's answer.
public static Object RunGetter(String fieldname, Object o){
Object result = null;
boolean found = false;
//Search this and all superclasses:
for (Class<?> clas = o.getClass(); clas != null; clas = clas.getSuperclass()){
if(found){
break;
}
//Find the correct method:
for (Method method : clas.getDeclaredMethods()){
if(found){
break;
}
//Method found:
if ((method.getName().startsWith("get")) && (method.getName().length() == (fieldname.length() + 3))){
if (method.getName().toLowerCase().endsWith(fieldname.toLowerCase())){
try{
result = method.invoke(o); //Invoke Getter:
found = true;
} catch (IllegalAccessException | InvocationTargetException ex){
Logger.getLogger("").log(Level.SEVERE, "Could not determine method: " + method.getName(), ex);
}
}
}
}
}
return result;
}
Hopefully that is useful to someone.
Do you perhaps mean from a different object an untrusted context with a SecurityManager
set? That would break the type system, so you can't. From a trusted context, you can call setAccessible
to defeat the type system. Ideally, don't use reflection.

- 145,806
- 30
- 211
- 305
-
"Ideally, don't use reflection." Why? The OP is specifically trying to use reflection...while he doesn't say why, there are many legitimate uses for reflection (especially in test code). – David Citron Apr 09 '09 at 18:19
-
Whilst there are legitimate uses of reflection, most are not. In particular if you are creeping around the legacy ability to respect Java (1.0) language access rules, you probably don't need it. – Tom Hawtin - tackline Apr 09 '09 at 18:40
-
@Tom ...unless you're trying to write specific JUnit test cases without loosening access rules simply for the test case – David Citron Apr 09 '09 at 22:30
-
Unit testing is "interesting". You could argue that it forces your code to be cleaner (alternatively unnecessarily general). Tests don't necessarily follow the usual rules of nice code. – Tom Hawtin - tackline Apr 09 '09 at 23:35
You could do something like...
Class clazz = Class.forName("SuperclassObject");
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("fieldImLookingFor")) {
field.set...() // ... should be the type, eg. setDouble(12.34);
}
}
You might also need to change the accessibility, as noted in Maurice's answer.

- 63,336
- 16
- 89
- 104

- 31,257
- 32
- 136
- 234
-
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. It didn't go through the super classes – Moro Apr 09 '09 at 18:06
-
Could you be more specific with the issue? You're saying it only obtained the fields in your subclass? Have you made sure that the Class.forName() method is being passed the name of the superclass, and that the accessibility has been modified, as Maurice suggested? – Craig Otis Apr 09 '09 at 18:17