0

I am trying to come up with a custom annotation, wanted to see if my use-case fit a allowed way of using custom annotation.

I want to replicate what Spring @Value does, but instead of reading a property off of a property, i want to my custom thing.

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

public Class TestEncrypted {

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

I am hoping in annotation processor, i decrypt value and set to the field 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;
    }
}

I get the variable, its return types and everything, but not sure how to set value of the variable from this annotation, even if i figure it out, is it good way of using custom annotations.

*Note: This might be sample, what I am planning to do is much more complicated than above sample.

  • 1
    What's the goal of this idea? Do you want to hide passwords or other sensitive information in the source text, and have them decrypted and placed in the byte code/class files? – markspace Jan 30 '18 at 16:44
  • this is an sample, but my real use case, secrets are stored in AWS dynamoDB encrypted with KMS, so i want to read the values at runtime and use them directly off of EC2. – Naveen Kumar Gurram Jan 30 '18 at 18:01

1 Answers1

0

There's no way to modify existing source files via the current publicly-available API. Tools like Lombok which do this are using undocumented internal Javac features to edit the abstract syntax tree. For example, you could use the Sun compiler tree API to obtain a VariableTree, cast it to a JCVariableDecl, then modify it and hope there are no unforeseen consequences. There's no guarantee that tools like Lombok will actually work, and they could break tomorrow with no warning.

What you could do instead is have the annotated classes reference a class which your annotation processor generates, as in the following example:

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";
}

Another way to do something like this would be to use the annotation processor to generate a factory object or method which creates instances of e.g. TestEncrypted with the field assigned to the decrypted value.

A good tutorial for code generation with annotation processors is here: https://deors.wordpress.com/2011/10/08/annotation-processors/


Also, as a side note in case you don't know this, String literals and names appear in the compiled class file, so none of these examples which decrypt the data at compile-time provide any security.

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • hmm.. I see, looks like some option, but that worries me is your point that these are string literal and can be seen at the compile-time. – Naveen Kumar Gurram Jan 30 '18 at 18:05
  • String literals referenced in source code appear in the compiled class file, so they can be discovered by inspecting the class file/jar file with an appropriate tool. See for example https://stackoverflow.com/q/10209952/2891664 – Radiodef Jan 30 '18 at 18:43
  • Thanks. I wonder how Spring @Value annotation works, may i can use their spel ability to invoke a method, that way I can have my class which decrypts the value and let Spring inject that value. – Naveen Kumar Gurram Jan 30 '18 at 18:59