使用自定义运行时注释设置属性值

时间:2018-01-30 16:36:30

标签: java annotations runtime annotation-processor

我试图想出一个自定义注释,想看看我的用例是否适合使用自定义注释的方法。

我想复制Spring @Value的功能,但不是从属性中读取属性,而是想要我自定义的东西。

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public @interface EncryptedValue {
   String value();
}

public Class TestEncrypted {

  @EncryptedValue("dGVzdCBzdHJpbmc=");
  public String someEncryptedValue;
}

我希望在注释处理器中,我解密值并设置为someEncryptedValue字段。

/**
 *
 */
@SupportedAnnotationTypes("annotation.EncryptedValue")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class CustomProcessor extends AbstractProcessor{

    private Types typeUtils;
    private Elements elementUtils;
    private Filer filer;
    private Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        typeUtils = processingEnv.getTypeUtils();
        elementUtils = processingEnv.getElementUtils();
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
            for(Element ele : annotatedElements) {
                EncryptedValue encryptedValue = ele.getAnnotation(EncryptedValue.class);
                if(!ele.getKind().isField()){
                    messager.printMessage(Diagnostic.Kind.ERROR,"EncryptedValue is supported for field");
                    return false;
                }
                String annotationValue = encryptedValue.value();
                // now get the enclosing type
                Set<Modifier> modifiers = ele.getModifiers();
                String nameOfVariable = ele.getSimpleName().toString();
                // check to see what fields we can modify (i think we can't modify static).
                messager.printMessage(Diagnostic.Kind.NOTE,"ClassType: "+ele.getSimpleName().toString()+", nameOf="+annotationValue);

                String simpleName = ele.getEnclosingElement().getSimpleName().toString();
                for (Element elem  : roundEnv.getRootElements()) {
                    messager.printMessage(Diagnostic.Kind.NOTE, "Enclosing ClassName: "+elem.getSimpleName().toString());
                    if (elem.getSimpleName().toString().equals(simpleName)) {
                        for (Element variableDeclaration : elem.getEnclosedElements()) {
                            if (variableDeclaration instanceof VariableElement) {
                                messager.printMessage(Diagnostic.Kind.NOTE, "variable: "+((VariableElement) variableDeclaration).getSimpleName().toString());

                            }
                        }
                    }
                }

            }
        }
        return true;
    }
}

我得到变量,它的返回类型和所有内容,但不知道如何从这个注释中设置变量的值,即使我弄明白,这是使用自定义注释的好方法。

*注意:这可能是样本,我打算做的比上面的样本复杂得多。

1 个答案:

答案 0 :(得分:0)

无法通过当前公开的API修改现有的源文件。像Lombok这样的工具使用未记录的内部Javac功能来编辑抽象语法树。例如,您可以使用Sun compiler tree API获取VariableTree,将其投放到JCVariableDecl,然后对其进行修改,并希望不会产生无法预料的后果。目前还不能保证像龙目岛这样的工具能够真正发挥作用,而且明天它们可能会在没有任何警告的情况下破坏。

您可以做的是让注释类引用注释处理器生成的类,如下例所示:

public class TestEncrypted {
    @EncryptedValue("dGVzdCBzdHJpbmc=");
    public String someEncryptedValue =
        TestEncryptedDecryptedValues.someEncryptedValue;
}

// then generate this class with the annotation processor
final class TestEncryptedDecryptedValues {
    static final String someEncryptedValue = "test string";
}

执行这样的操作的另一种方法是使用注释处理器来生成工厂对象或方法,该工厂对象或方法创建例如实例。 TestEncrypted将字段分配给解密值。

使用注释处理器生成代码的好教程如下:https://deors.wordpress.com/2011/10/08/annotation-processors/

另外,作为附注,如果您不知道这一点,String文字和名称会出现在已编译的类文件中,因此这些在编译时解密数据的示例都不提供任何安全