1 package com.github.javaparser.generator.metamodel; 2 3 import com.github.javaparser.ast.CompilationUnit; 4 import com.github.javaparser.ast.Node; 5 import com.github.javaparser.ast.NodeList; 6 import com.github.javaparser.ast.body.*; 7 import com.github.javaparser.ast.stmt.Statement; 8 import com.github.javaparser.metamodel.DerivedProperty; 9 import com.github.javaparser.metamodel.InternalProperty; 10 import com.github.javaparser.utils.SourceRoot; 11 12 import java.lang.reflect.Field; 13 import java.lang.reflect.Method; 14 import java.util.ArrayList; 15 import java.util.Arrays; 16 import java.util.Comparator; 17 import java.util.List; 18 19 import static com.github.javaparser.StaticJavaParser.*; 20 import static com.github.javaparser.ast.Modifier.Keyword.*; 21 import static com.github.javaparser.generator.metamodel.MetaModelGenerator.*; 22 import static com.github.javaparser.utils.CodeGenerationUtils.f; 23 import static com.github.javaparser.utils.CodeGenerationUtils.optionalOf; 24 import static com.github.javaparser.utils.Utils.decapitalize; 25 26 public class NodeMetaModelGenerator { 27 private final InitializePropertyMetaModelsStatementsGenerator initializePropertyMetaModelsStatementsGenerator = new InitializePropertyMetaModelsStatementsGenerator(); 28 private final InitializeConstructorParametersStatementsGenerator initializeConstructorParametersStatementsGenerator = new InitializeConstructorParametersStatementsGenerator(); 29 generate(Class<? extends Node> nodeClass, ClassOrInterfaceDeclaration metaModelCoid, NodeList<Statement> initializeNodeMetaModelsStatements, NodeList<Statement> initializePropertyMetaModelsStatements, NodeList<Statement> initializeConstructorParametersStatements, SourceRoot sourceRoot)30 public void generate(Class<? extends Node> nodeClass, ClassOrInterfaceDeclaration metaModelCoid, NodeList<Statement> initializeNodeMetaModelsStatements, NodeList<Statement> initializePropertyMetaModelsStatements, NodeList<Statement> initializeConstructorParametersStatements, SourceRoot sourceRoot) throws NoSuchMethodException { 31 final String className = nodeMetaModelName(nodeClass); 32 final String nodeMetaModelFieldName = decapitalize(className); 33 metaModelCoid.getFieldByName(nodeMetaModelFieldName).ifPresent(Node::remove); 34 35 final FieldDeclaration nodeField = metaModelCoid.addField(className, nodeMetaModelFieldName, PUBLIC, STATIC, FINAL); 36 37 final Class<?> superclass = nodeClass.getSuperclass(); 38 final String superNodeMetaModel = nodeMetaModelName(superclass); 39 40 boolean isRootNode = !isNode(superclass); 41 nodeField.getVariable(0).setInitializer(parseExpression(f("new %s(%s)", 42 className, 43 optionalOf(decapitalize(superNodeMetaModel), !isRootNode)))); 44 45 initializeNodeMetaModelsStatements.add(parseStatement(f("nodeMetaModels.add(%s);", nodeMetaModelFieldName))); 46 47 final CompilationUnit classMetaModelJavaFile = new CompilationUnit(METAMODEL_PACKAGE); 48 classMetaModelJavaFile.addImport("java.util.Optional"); 49 sourceRoot.add(METAMODEL_PACKAGE, className + ".java", classMetaModelJavaFile); 50 final ClassOrInterfaceDeclaration nodeMetaModelClass = classMetaModelJavaFile.addClass(className, PUBLIC); 51 if (isRootNode) { 52 nodeMetaModelClass.addExtendedType(BASE_NODE_META_MODEL); 53 } else { 54 nodeMetaModelClass.addExtendedType(superNodeMetaModel); 55 } 56 57 final AstTypeAnalysis typeAnalysis = new AstTypeAnalysis(nodeClass); 58 59 final ConstructorDeclaration classMMConstructor = nodeMetaModelClass 60 .addConstructor() 61 .addParameter("Optional<" + BASE_NODE_META_MODEL + ">", "super" + BASE_NODE_META_MODEL); 62 classMMConstructor 63 .getBody() 64 .addStatement(parseExplicitConstructorInvocationStmt(f("super(super%s, %s.class, \"%s\", \"%s\", %s, %s);", 65 BASE_NODE_META_MODEL, 66 nodeClass.getName(), 67 nodeClass.getSimpleName(), 68 nodeClass.getPackage().getName(), 69 typeAnalysis.isAbstract, 70 typeAnalysis.isSelfType))); 71 72 if (typeAnalysis.isAbstract) { 73 classMetaModelJavaFile.addImport(Node.class); 74 nodeMetaModelClass.addMember(parseBodyDeclaration(f( 75 "protected %s(Optional<BaseNodeMetaModel> superNodeMetaModel, Class<? extends Node> type, String name, String packageName, boolean isAbstract, boolean hasWildcard) {" + 76 "super(superNodeMetaModel, type, name, packageName, isAbstract, hasWildcard);" + 77 " }", 78 className))); 79 } 80 81 final List<Field> fields = new ArrayList<>(Arrays.asList(nodeClass.getDeclaredFields())); 82 fields.sort(Comparator.comparing(Field::getName)); 83 for (Field field : fields) { 84 if (fieldShouldBeIgnored(field)) { 85 continue; 86 } 87 88 initializePropertyMetaModelsStatementsGenerator.generate(field, nodeMetaModelClass, nodeMetaModelFieldName, initializePropertyMetaModelsStatements); 89 } 90 final List<Method> methods = new ArrayList<>(Arrays.asList(nodeClass.getMethods())); 91 methods.sort(Comparator.comparing(Method::getName)); 92 for (Method method : methods) { 93 if (method.isAnnotationPresent(DerivedProperty.class)) { 94 initializePropertyMetaModelsStatementsGenerator.generateDerivedProperty(method, nodeMetaModelClass, nodeMetaModelFieldName, initializePropertyMetaModelsStatements); 95 } 96 } 97 98 initializeConstructorParametersStatementsGenerator.generate(nodeClass, initializeConstructorParametersStatements); 99 100 moveStaticInitializeToTheEndOfTheClassBecauseWeNeedTheFieldsToInitializeFirst(metaModelCoid); 101 } 102 moveStaticInitializeToTheEndOfTheClassBecauseWeNeedTheFieldsToInitializeFirst(ClassOrInterfaceDeclaration metaModelCoid)103 private void moveStaticInitializeToTheEndOfTheClassBecauseWeNeedTheFieldsToInitializeFirst(ClassOrInterfaceDeclaration metaModelCoid) { 104 for (BodyDeclaration<?> m : metaModelCoid.getMembers()) { 105 if (m instanceof InitializerDeclaration) { 106 m.remove(); 107 metaModelCoid.addMember(m); 108 return; 109 } 110 } 111 } 112 fieldShouldBeIgnored(Field reflectionField)113 private boolean fieldShouldBeIgnored(Field reflectionField) { 114 return java.lang.reflect.Modifier.isStatic(reflectionField.getModifiers()) || 115 reflectionField.isAnnotationPresent(InternalProperty.class); 116 } 117 } 118