使用反射在泛型类中设置注解字段的值。(IllegalArgumentException)

huangapple go评论86阅读模式
英文:

Setting annotated field value using reflection in generic class. (IllegalArgumentException)

问题

我一直遇到一个问题,涉及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)

对我来说,不太明白为什么反射无法将java.lang.String值分配给java.lang.String字段,正如IllegalArgumentException消息所说。我一定漏掉了什么,但我似乎找不到答案。

感谢任何帮助!

英文:

I have been facing an issue that implies Reflection, Annotations and Generics in Java. I have a class that creates a new instance of a generic type called B. Then it will search for any Field with the MyCustomAnnotation annotation and sets its value to a determined one.

The class that does this is:

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

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

The annotation class:

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

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

The custom type has an annotated Field of type String:

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

Finally my main class is:

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

The output of the program is:

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)

It does not make any sense to me why reflection cannot assign a java.lang.String value to a java.lang.String field as the IllegalArgumentException message says. I must be missing something but I can't seem to figure it out.

Any help is appreciated!

答案1

得分: 1

以下是您的问题:

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

以下是您的修复:

这里是您的修复...

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

这里是文档:

这里是文档...

public void set​(Object obj, Object value)...

...

Parameters:

obj - 应修改其字段的对象

value - 要修改的 obj 字段的新值...

> &hellip;

英文:

Here's your problem&hellip;

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

Here's your fix&hellip;

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

Here are the docs&hellip;
>
> public void set​(Object obj, Object value)&hellip;
>
> ...
>
> Parameters:
>
> obj - the object whose field should be modified
>
> value - the new value for the field of obj being modified
>
> &hellip;

huangapple
  • 本文由 发表于 2020年8月3日 23:46:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63232658.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定