リフレクションによってオブジェクトから継承された保護フィールドにアクセスするにはどうすればよいですか?
11 に答える
問題が発生している可能性のある2つの問題-フィールドは通常はアクセスできない可能性があり(プライベート)、表示しているクラスではなく、階層のどこかにあります。
このようなものは、これらの問題でも機能します。
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);
}
}
FieldUtils.writeField(object, "fieldname", value, true)
またはApache Commons lang3readField(object, "fieldname", true)
から使用します。
リフレクションを使用して、クラス インスタンスのメンバーにアクセスし、アクセスできるようにして、それぞれの値を設定します。もちろん、変更したい各メンバーの名前を知っている必要がありますが、それは問題にはならないと思います.
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));
}
}
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);
Spring を使用している場合、ReflectionTestUtilsは、最小限の労力でここで役立ついくつかの便利なツールを提供します。
たとえば、 であることがわかっている保護されたフィールド値を取得するには、次のようにしint
ます。
int theIntValue = (int)ReflectionTestUtils.getField(theClass, "theProtectedIntField");
または、このフィールドの値を設定するには:
ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue);
保護されたフィールドを取得するだけの場合
Field protectedfield = Myclazz.class.getSuperclass().getDeclaredField("num");
Eclipse Ctrl+Spaceを使用している場合、「.」を入力するとメソッドのリストが表示されます。オブジェクトの後
これ以上ライブラリをドラッグしたくなかったので、自分に合った純粋なライブラリを作成しました。これは、jweyrich のメソッドの 1 つを拡張したものです。
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);
}
}
}
おそらく、別のオブジェクトから、セットを持つ信頼できないコンテキストを意味していSecurityManager
ますか? それは型システムを壊すので、できません。setAccessible
信頼されたコンテキストから、型システムを打ち負かすために呼び出すことができます。理想的には、リフレクションを使用しないでください。
あなたは次のようなことができます...
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);
}
}
Maurice's answer に記載されているように、アクセシビリティを変更する必要がある場合もあります。
このクラスまたは任意のスーパークラスで任意の getter を実行する汎用ユーティリティ メソッド。
マリウスの答えから適応。
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;
}
うまくいけば、それは誰かに役立ちます。