【问题标题】:Setting annotated field value using reflection in generic class. (IllegalArgumentException)在泛型类中使用反射设置带注释的字段值。 (IllegalArgumentException)
【发布时间】:2020-08-03 15:46:24
【问题描述】:

我一直面临一个问题,它暗示 Java 中的反射、注释和泛型。我有一个类,它创建一个名为B 的泛型类型的新实例。然后它将搜索带有MyCustomAnnotation 注释的任何Field 并将其值设置为确定的值。

执行此操作的类是:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class MyInstanceCreator<B> {
    
    private final String myValue = "Hello world!";
    
    public B createInstance(Class<B> classType) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        B obj = classType.getConstructor().newInstance();
        for(Field f: classType.getDeclaredFields()) {
            if(f.isAnnotationPresent(MyCustomAnnotation.class)) {
                System.out.println("Is annotated!");
                updateField(obj, f);
            }
        }
        return obj;
    }
    
    private void updateField(B instance, Field field) throws IllegalAccessException {
        field.setAccessible(true);
        field.set(myValue, instance);
        field.setAccessible(false);
    }
    
}

注解类:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation {}

自定义类型有一个 String 类型的注释字段:

public class MyCustomType {
    
    @MyCustomAnnotation
    private String value;
    
    public String getValue() {
        return value;
    }
    
}

最后我的主要课程是:

public class MyClass {
    public static void main(String args[]) {
        try {
            MyInstanceCreator<MyCustomType> iCreator = new MyInstanceCreator<>();
            MyCustomType myObj = iCreator.createInstance(MyCustomType.class);
            System.out.println(myObj.getValue());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

程序的输出是:

Is annotated!

java.lang.IllegalArgumentException: Can not set java.lang.String field MyCustomType.value to java.lang.String
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.base/java.lang.reflect.Field.set(Field.java:780)
    at MyInstanceCreator.updateField(MyInstanceCreator.java:21)
    at MyInstanceCreator.createInstance(MyInstanceCreator.java:13)
    at MyClass.main(MyClass.java:5)

正如IllegalArgumentException 消息所说,为什么反射不能将java.lang.String 值分配给java.lang.String 字段对我来说没有任何意义。我一定是错过了什么,但我似乎无法弄清楚。

感谢任何帮助!

【问题讨论】:

    标签: java generics reflection annotations


    【解决方案1】:

    这是你的问题……

    ...
    field.set(myValue, instance);
    ...
    

    Here's your fix

    ...
    field.set(instance, myValue);
    ...
    

    Here are the docs

    public void set​(Object obj, Object value)

    ...

    参数:

    obj - 应该修改其字段的对象

    value - 被修改的 obj 字段的新值

    【讨论】:

    • 不,你不傻。因为如果你笨,那我也笨。哈哈。直到尝试了两三个不太简单的修复后,我才发现出了什么问题。如果像我一样,您没有经常使用该 Field.set(Object, Object) 方法,那么很容易混淆哪个 Object 参数是哪个。所以不要出汗:)
    猜你喜欢
    • 2012-11-04
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多