Итак, я пишу преобразование AST, которое добавляет поле с аннотацией @Delegate к классу
@SimpleAST
class PersonBuilder{
}
Должно выдать
class PersonBuilder{
@Delegate
Person target = new Person
}
Мой интерфейс:
@Retention(RetentionPolicy.RUNTIME)
@Target([ElementType.TYPE])
@GroovyASTTransformationClass("poc.SimpleASTTransformation")
public @interface SimpleAST {
/**
* A class for which builder methods should be created. It will be an error to leave
* this attribute with its default value for some strategies.
*/
Class value()
}
Мое преобразование:
@CompileStatic
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class SimpleASTTransformation implements ASTTransformation {
@Override
void visit(ASTNode[] astNodes, SourceUnit source) {
ClassNode classNode = (ClassNode) astNodes[1]
if (!astNodes) return
if (!astNodes[0]) return
if (!astNodes[1]) return
if (!(astNodes[0] instanceof AnnotationNode)) return
if (!(astNodes[1] instanceof ClassNode)) return
println "Running AST Transformation for ${classNode.getNameWithoutPackage()}..."
AnnotationNode annotationNode = (AnnotationNode) astNodes[0]
ClassExpression classExpression = (ClassExpression) annotationNode.getMember("value")
String packageName = classNode.getPackageName()
String builderClassNameWithoutPackage = classNode.getNameWithoutPackage()
String originalClassNameWithPackage = classExpression.getText()
originalClassNameWithPackage = Validate.checkOriginalClassName(originalClassNameWithPackage)
Class<?> originalClass = Class.forName(originalClassNameWithPackage)
ClassNode originalClassNode = new ClassNode(originalClass)
String originalClassNameWithoutPackage = originalClassNode.getNameWithoutPackage()
println "Generating methods for $originalClassNameWithoutPackage..."
generateTargetField(classNode,originalClass)
println "Transformation applied!"
}
static void generateTargetField(ClassNode classNode, Class originalClass){
ClassNode originalClassNode = new ClassNode(originalClass)
ConstructorCallExpression constructorCallExpression = new ConstructorCallExpression(originalClassNode,new ArgumentListExpression())
FieldNode fieldNode = new FieldNode("target",
2,
originalClassNode,
classNode,
constructorCallExpression)
ArrayList<AnnotationNode> annotationNodes = new ArrayList<>()
annotationNodes.add(new AnnotationNode(new ClassNode(Delegate)))
fieldNode.addAnnotations(annotationNodes)
classNode.addField(fieldNode)
}
}
Когда я проверяю байт-код, в полях класса Person нет методов получения / установки (я использовал @Delegate для целевого поля)
Однако, если я просто добавлю поле вручную и скомпилирую код, я получу методы получения и установки для полей в классе Person.
У Person есть 2 поля: firstName, lastName и Strings.