2016-07-29 31 views
2

Ich möchte einige Klassen zur Kompilierzeit ein generisches Feld hinzufügen. Zu diesem Zweck implementierte ich meine eigenen AST-Annotations- und Transformationsklassen, indem ich die offizielle documentation befolgte und gewünschte Klassen mit AST-Annotationen annotierte.GroovyAST generisches Feld zur Kompilierzeit hinzufügen

Aber ich erhalte diesen Fehler bei der Kompilierung:

org.codehaus.groovy.control.MultipleCompilationErrorsException: Start nicht gestartet: /home/.../groovy/Sample.groovy: -1: Eine Transformation verwendete eine Generika, die ClassNode java.util.HashSet für das Feld x direkt enthielt. Du solltest das nicht tun. Bitte erstellen Sie einen neuen ClassNode, der sich auf den alten ClassNode bezieht, und verwenden Sie den neuen ClassNode anstelle des alten. Andernfalls erstellt der Compiler in TypeResolver in OpenJDK falsche Deskriptoren und eine mögliche NullPointerException. Wenn dies nicht Ihre eigene Aufgabe ist, melden Sie diesen Fehler bitte dem Verfasser der Transformation. @ Zeile -1, Spalte -1.

Habe ich einen Fehler gemacht?

Beispielcodes

Zum Beispiel nehme ich an x, durch MyAST Anmerkung kommentiert zu jeder Klasse ein HashSet<Long> Feld, mit dem Namen hinzufügen möchten.

Meine AST Annotation-Klasse:

@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.TYPE) 
@GroovyASTTransformationClass(classes = [MyASTTransformation.class]) 
public @interface MyAST { 
} 

Meine AST Transformationsklasse:

@CompileStatic 
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) 
public class MyASTTransformation implements ASTTransformation { 

@Override 
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) { 
    ClassNode clazz = (ClassNode) nodes[1]; 
    ClassNode longHashSetClass = new ClassNode(HashSet.class); 
    longHashSetClass.setGenericsTypes([new GenericsType(new ClassNode(Long.class))] as GenericsType[]); 
    FieldNode field = new FieldNode("x", FieldNode.ACC_PRIVATE, longHashSetClass, clazz, new ConstantExpression(null)); 
    clazz.addField(field); 
} 
} 

Beispiel kommentierte Klasse:

@MyAST 
public class Sample { 
} 

Hinweis

Wenn ich die Zeile longHashSetClass.setGenericsTypes([new GenericsType(new ClassNode(Long.class))] as GenericsType[]); eliminiere, ist alles in Ordnung, aber der Typ x ist HashSet statt HashSet<Long> zur Laufzeit.

Antwort

2

Sie sollten ClassHelper oder GenericUtils verwenden, um eine ClassNode zu erstellen:

import static org.codehaus.groovy.ast.ClassHelper.make 
import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafeWithGenerics 

... 

ClassNode hashSet = makeClassSafeWithGenerics(HashSet, make(Long)) 
+0

Danke. Es funktioniert, aber wenn ich 'make (HashSet)' zu 'new ClassNode (HashSet)' 'ändere, erhalte ich einen Fehler. Was ist zwischen ihnen anders? – vahidreza

+0

Ehrlich gesagt, ich weiß es nicht, aber ClassNode sollte nicht direkt instanziiert werden. Diese Methoden verarbeiten Caching, Aliasing und andere Dinge, die beim Generieren von Bytecodes notwendig sind. –