【问题标题】:Updating field attributes by annotation通过注解更新字段属性
【发布时间】:2018-03-27 16:54:16
【问题描述】:

我正在审查反射的工作方式或可能的工作方式。我有这个SomeClassBuilder,其中它有一个属性target : Target,声明了注释TargetAnnotation

问题是,是否可以覆盖/更新 Target 的值/属性,其中在调用 someMethod() 时会返回注释上的参数?

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TargetAnnotation {
    String first();
    String second();
    // other attributes
}

public class Target {
    String first;
    String second;
    // some other attributes unique only to `Target`
}

public interface TargetHelper {
    void setTarget(Target target);
}

public class SomeClassBuilder implements TargetHelper {

    @TargetAnnotation(first = "first", second = "second")
    private Target target;

    @Override public void setTarget(Target target) { this.target = target }

    public void someMethod() {
        System.out.println(target.first); // should be `first`
        System.out.println(target.second); // should be `second`
    }

}

或者甚至可以在没有TargetHelper 接口的情况下做到这一点?

假设我在SomeClassBuilder 之前调用了这个TargetProcessor,其唯一目的是填写带有@TargetAnnotation 注释的target : Target,并将@TargetAnnotaton 中的字段/属性分配给Target

public class TargetProcessor {
    public void parse() {
        // look into `@TargetAnnotation`
        // map `@TargetAnnotation` properties to `Target`
    }
}

【问题讨论】:

  • 如果我理解这一点,你会得到一个字段,上面有一个注释,定义了该字段的值,对吧?
  • @CodeMatrix,是的。请查看更新内容。
  • 您可以使用Processor或通过工厂方法创建实例。后面我可以举个例子。

标签: java reflection annotations java-annotations


【解决方案1】:

这是我的代码

import static xdean.jex.util.lang.ExceptionUtil.uncheck;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.stream.Stream;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import xdean.jex.util.reflect.ReflectUtil;

public class Q46765735 {

  public static void main(String[] args) {
    create(TargetDomain.class).printTarget();
  }

  public static <T> T create(Class<T> clz) {
    T target = uncheck(() -> clz.newInstance());
    Stream.of(ReflectUtil.getAllFields(clz, false)).forEach(f -> uncheck(() -> fill(target, f)));
    return target;
  }

  private static <T> void fill(T target, Field field) throws Exception {
    TargetAnnotation anno = field.getAnnotation(TargetAnnotation.class);
    if (anno == null) {
      return;
    }
    Class<?> type = field.getType();
    if (!Target.class.isAssignableFrom(type)) {
      return;
    }
    field.setAccessible(true);
    Target value = (Target) field.get(target);
    if (value == null) {
      value = (Target) type.newInstance();
    }
    value.setFirst(anno.first());
    value.setSecond(anno.second());
    field.set(target, value);
  }
}

@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({ ElementType.FIELD })
@interface TargetAnnotation {
  String first();

  String second();
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Target {
  String first;
  String second;
}

class TargetDomain {

  @TargetAnnotation(first = "first", second = "second")
  private Target target = new Target("a", "b");

  public void printTarget() {
    System.out.println(target.first); // should be `first`
    System.out.println(target.second); // should be `second`
  }
}


提示:

  1. 您可以通过手动编写构造函数和 getter/setter 来替换 lombok。
  2. ReflectUtil.getAllFields获取类的所有字段。
  3. uncheck 只是忽略异常,可以使用try-catch。

【讨论】:

    【解决方案2】:

    【讨论】:

    • 这里使用Maven进行编译。下面的示例您也可以在没有 maven 编译的情况下进行操作。 javacodegeeks.com/2015/09/java-annotation-processors.html
    • 查看我在最后一个链接中提到的文章
    • 对我来说仍然不是解决方案,因为我无法调用 AbstractProcessor 的任何类
    • 你不需要调用任何类,但你需要像-processor YourAnnotationProcessor 类一样在编译时提供
    猜你喜欢
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    相关资源
    最近更新 更多