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

Setting property value with custom runtime annotation

我正在尝试提出自定义注释,想看看我的用例是否适合使用自定义注释的允许方式。

我想复制 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;
    }
}

我得到了变量,它的 return 类型和所有内容,但不确定如何从此注释设置变量的值,即使我弄清楚了,这是使用自定义注释的好方法。

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

无法通过当前公开可用的 API 修改现有源文件。执行此操作的工具(如 Lombok)使用未记录的内部 Javac 功能来编辑抽象语法树。例如,您可以使用 Sun compiler tree API to obtain a VariableTree, cast it to a JCVariableDecl,然后修改它并希望不会出现不可预见的后果。不能保证像 Lombok 这样的工具会真正工作,它们明天可能会在没有警告的情况下崩溃。

您可以改为让带注释的 classes 引用您的注释处理器生成的 class,如以下示例所示:

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 文字和名称出现在已编译的 class 文件中,因此 none 这些示例解密编译时的数据提供任何安全性。