Установка значения свойства с пользовательской аннотацией времени выполнения
Я пытаюсь придумать пользовательскую аннотацию, хотел посмотреть, соответствует ли мой вариант использования разрешенному способу использования пользовательской аннотации.
Я хочу повторить то, что делает 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 ответ
Нет никакого способа изменить существующие исходные файлы через текущий общедоступный API. Такие инструменты, как Lombok, которые делают это, используют недокументированные внутренние функции Javac для редактирования абстрактного синтаксического дерева. Например, вы можете использовать API дерева компилятора Sun для получения VariableTree
брось это 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
литералы и имена появляются в скомпилированном файле класса, поэтому ни один из этих примеров, который расшифровывает данные во время компиляции, не обеспечивает никакой безопасности.