0

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

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

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

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

4

1 回答 1

0

无法通过当前公开的 API 修改现有源文件。像 Lombok 这样的工具使用未记录的内部 Javac 特性来编辑抽象语法树。例如,您可以使用Sun 编译器树 API获取 a VariableTree,将其转换为 a JCVariableDecl,然后对其进行修改并希望没有不可预见的后果。不能保证像 Lombok 这样的工具会真正起作用,而且它们明天可能会在没有任何警告的情况下崩溃。

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

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

于 2018-01-30T17:06:11.730 回答