com.github.javaparser.generator.metamodel.NodeMetaModelGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javaparser-metamodel-generator Show documentation
Show all versions of javaparser-metamodel-generator Show documentation
The tool that generates the code in the javaparser-metamodel module
package com.github.javaparser.generator.metamodel;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.metamodel.DerivedProperty;
import com.github.javaparser.utils.SourceRoot;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static com.github.javaparser.JavaParser.*;
import static com.github.javaparser.ast.Modifier.*;
import static com.github.javaparser.generator.metamodel.MetaModelGenerator.*;
import static com.github.javaparser.utils.CodeGenerationUtils.f;
import static com.github.javaparser.utils.CodeGenerationUtils.optionalOf;
import static com.github.javaparser.utils.Utils.decapitalize;
public class NodeMetaModelGenerator {
private final InitializePropertyMetaModelsStatementsGenerator initializePropertyMetaModelsStatementsGenerator = new InitializePropertyMetaModelsStatementsGenerator();
private final InitializeConstructorParametersStatementsGenerator initializeConstructorParametersStatementsGenerator = new InitializeConstructorParametersStatementsGenerator();
public void generate(Class extends Node> nodeClass, ClassOrInterfaceDeclaration metaModelCoid, NodeList initializeNodeMetaModelsStatements, NodeList initializePropertyMetaModelsStatements, NodeList initializeConstructorParametersStatements, SourceRoot sourceRoot) throws NoSuchMethodException {
final String className = nodeMetaModelName(nodeClass);
final String nodeMetaModelFieldName = decapitalize(className);
metaModelCoid.getFieldByName(nodeMetaModelFieldName).ifPresent(Node::remove);
final FieldDeclaration nodeField = metaModelCoid.addField(className, nodeMetaModelFieldName, PUBLIC, STATIC, FINAL);
final Class> superclass = nodeClass.getSuperclass();
final String superNodeMetaModel = nodeMetaModelName(superclass);
boolean isRootNode = !isNode(superclass);
nodeField.getVariable(0).setInitializer(parseExpression(f("new %s(%s)",
className,
optionalOf(decapitalize(superNodeMetaModel), !isRootNode))));
initializeNodeMetaModelsStatements.add(parseStatement(f("nodeMetaModels.add(%s);", nodeMetaModelFieldName)));
final CompilationUnit classMetaModelJavaFile = new CompilationUnit(METAMODEL_PACKAGE);
classMetaModelJavaFile.addImport("java.util.Optional");
sourceRoot.add(METAMODEL_PACKAGE, className + ".java", classMetaModelJavaFile);
final ClassOrInterfaceDeclaration nodeMetaModelClass = classMetaModelJavaFile.addClass(className, PUBLIC);
if (isRootNode) {
nodeMetaModelClass.addExtendedType(BASE_NODE_META_MODEL);
} else {
nodeMetaModelClass.addExtendedType(superNodeMetaModel);
}
final AstTypeAnalysis typeAnalysis = new AstTypeAnalysis(nodeClass);
final ConstructorDeclaration classMMConstructor = nodeMetaModelClass
.addConstructor()
.addParameter("Optional<" + BASE_NODE_META_MODEL + ">", "super" + BASE_NODE_META_MODEL);
classMMConstructor
.getBody()
.addStatement(parseExplicitConstructorInvocationStmt(f("super(super%s, %s.class, \"%s\", \"%s\", %s, %s);",
BASE_NODE_META_MODEL,
nodeClass.getName(),
nodeClass.getSimpleName(),
nodeClass.getPackage().getName(),
typeAnalysis.isAbstract,
typeAnalysis.isSelfType)));
if (typeAnalysis.isAbstract) {
classMetaModelJavaFile.addImport(Node.class);
nodeMetaModelClass.addMember(parseClassBodyDeclaration(f(
"protected %s(Optional superNodeMetaModel, Class extends Node> type, String name, String packageName, boolean isAbstract, boolean hasWildcard) {" +
"super(superNodeMetaModel, type, name, packageName, isAbstract, hasWildcard);" +
" }",
className)));
}
final List fields = new ArrayList<>(Arrays.asList(nodeClass.getDeclaredFields()));
fields.sort(Comparator.comparing(Field::getName));
for (Field field : fields) {
if (fieldShouldBeIgnored(field)) {
continue;
}
initializePropertyMetaModelsStatementsGenerator.generate(nodeClass, field, nodeMetaModelClass, nodeMetaModelFieldName, initializePropertyMetaModelsStatements);
}
for (Method method : nodeClass.getMethods()) {
if (method.isAnnotationPresent(DerivedProperty.class)) {
initializePropertyMetaModelsStatementsGenerator.generateDerivedProperty(nodeClass, method, nodeMetaModelClass, nodeMetaModelFieldName, initializePropertyMetaModelsStatements);
}
}
if (!typeAnalysis.isAbstract) {
initializeConstructorParametersStatementsGenerator.generate(nodeClass, initializeConstructorParametersStatements);
}
moveStaticInitializeToTheEndOfTheClassBecauseWeNeedTheFieldsToInitializeFirst(metaModelCoid);
}
private void moveStaticInitializeToTheEndOfTheClassBecauseWeNeedTheFieldsToInitializeFirst(ClassOrInterfaceDeclaration metaModelCoid) {
for (BodyDeclaration> m : metaModelCoid.getMembers()) {
if (m instanceof InitializerDeclaration) {
m.remove();
metaModelCoid.addMember(m);
return;
}
}
}
private boolean fieldShouldBeIgnored(Field reflectionField) {
if (java.lang.reflect.Modifier.isStatic(reflectionField.getModifiers())) {
return true;
}
String name = reflectionField.getName();
switch (name) {
case "parentNode":
case "observers":
case "innerList":
case "data":
case "range":
case "childNodes":
case "commentedNode":
case "orphanComments":
return true;
}
return false;
}
}