我有这个:
package general;
import org.junit.Test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
@Retention(RetentionPolicy.RUNTIME)
@interface SetTable {
String table();
}
class Star {
public String foo = "";
public String toString(){
return "<Star> : " + this.foo;
}
}
class Bar {
@SetTable(table = "xxx")
public Star s = new Star();
public String toString(){
return "<Bar> : " + this.s.toString();
}
}
class AnnotationInjector {
public static void inject(Object instance) {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SetTable.class)) {
SetTable set = field.getAnnotation(SetTable.class);
field.setAccessible(true); // should work on private fields
try {
field.set(instance, set.table()); // this is not what I need
// ***
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public class AnnotationTest {
@Test
public void first() {
var b = new Bar();
AnnotationInjector.inject(b);
System.out.println(b.toString());
}
}
现在,代码正在尝试将新的Bar()。s设置为字符串,但这将不起作用,因为新的Bar()。s需要是实例Star。但这不是我想做的。我想做的是access并设置它:
new Bar().s.foo = "whatever"
在***指定的上面的行上
我正在做类似的事情:
((Star)field).foo = "whatever";
但这是不对的。分配字段后可以修改字段吗?
答案 0 :(得分:0)
相反,执行此操作的语法是:
Star x = (Star)field.get(instance);
此行可以修改Star s
上预先存在的Bar
字段的属性。
答案 1 :(得分:0)
作为替代方案,我建议您添加一个interface
来设置值的方法,以使设置值更通用,而不是检查实例及其类型,并使Star
类实现如下:
interface ISetValue {
void setValue(String value);
}
class Star implements ISetValue{
public String foo = "";
@Override
public void setValue(String value) {
foo = value;
}
public String toString(){
return "<Star> : " + this.foo;
}
}
您的AnnotationInjector
类应检查该字段是否实现了ISetValue
并为其调用setValue
方法,如下所示:
class AnnotationInjector {
public static void inject(Object instance) {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SetTable.class)) {
SetTable set = field.getAnnotation(SetTable.class);
field.setAccessible(true); // should work on private fields
try {
//field.set(instance, set.table()); // this is not what I need
// ***
//Change is here
Class fieldType = field.getType();
if(ISetValue.class.isAssignableFrom(fieldType) ){
Object fieldValue = field.get(instance);
Method myMethod = fieldValue.getClass().getInterfaces()[0].getDeclaredMethod("setValue", new Class[]{String.class});
myMethod.invoke(fieldValue,set.table());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
现在您的输出应该是:
<Bar> : <Star> : xxx