• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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