0

我正在审查反思的工作方式或可能的工作方式。我有这个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接口的情况下做到这一点?

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

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

2 回答 2

0

这是我的代码

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。
于 2017-10-27T09:22:59.130 回答
0

您可以通过为您的注释@TargetAnnotation实现注释处理器来实现这一点

如需进一步阅读和示例:

  1. http://www.baeldung.com/java-annotation-processing-builder
  2. https://github.com/bozaro/example-annotation-processor/blob/master/example-modify/processor/src/main/java/ru/bozaro/processor/HelloProcessor.java
  3. https://deors.wordpress.com/2011/10/08/annotation-processors/

这篇文章解释了应该如何做:

  1. http://hannesdorfmann.com/annotation-processing/annotationprocessing101
于 2017-10-16T08:24:38.197 回答