/* |
|
* Copyright (C) 2007-2010 Júlio Vilmar Gesser. |
|
* Copyright (C) 2011, 2013-2021 The JavaParser Team. |
|
* |
|
* This file is part of JavaParser. |
|
* |
|
* JavaParser can be used either under the terms of |
|
* a) the GNU Lesser General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* b) the terms of the Apache License |
|
* |
|
* You should have received a copy of both licenses in LICENCE.LGPL and |
|
* LICENCE.APACHE. Please refer to those files for details. |
|
* |
|
* JavaParser is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU Lesser General Public License for more details. |
|
*/ |
|
package com.github.javaparser.metamodel; |
|
import com.github.javaparser.ast.AllFieldsConstructor; |
|
import com.github.javaparser.ast.Node; |
|
import com.github.javaparser.ast.NodeList; |
|
import java.lang.reflect.Constructor; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.util.*; |
|
import static com.github.javaparser.utils.Utils.decapitalize; |
|
/** |
|
* Meta-data about all classes in the AST. These are all Nodes, except NodeList. |
|
*/ |
|
public abstract class BaseNodeMetaModel { |
|
private final Optional<BaseNodeMetaModel> superNodeMetaModel; |
|
private final List<PropertyMetaModel> declaredPropertyMetaModels = new ArrayList<>(); |
|
private final List<PropertyMetaModel> derivedPropertyMetaModels = new ArrayList<>(); |
|
private final List<PropertyMetaModel> constructorParameters = new ArrayList<>(); |
|
private final Class<? extends Node> type; |
|
private final String name; |
|
private final String packageName; |
|
private final boolean isAbstract; |
|
private final boolean hasWildcard; |
|
public BaseNodeMetaModel(Optional<BaseNodeMetaModel> superNodeMetaModel, Class<? extends Node> type, String name, String packageName, boolean isAbstract, boolean hasWildcard) { |
|
this.superNodeMetaModel = superNodeMetaModel; |
|
this.type = type; |
|
this.name = name; |
|
this.packageName = packageName; |
|
this.isAbstract = isAbstract; |
|
this.hasWildcard = hasWildcard; |
|
} |
|
/** |
|
* @return is this the meta model for this node class? |
|
*/ |
|
public boolean is(Class<? extends Node> c) { |
|
return type.equals(c); |
|
} |
|
/** |
|
* @return package name + class name |
|
*/ |
|
public String getQualifiedClassName() { |
|
return packageName + "." + name; |
|
} |
|
/** |
|
* @return the meta model for the node that this node extends. Note that this is to be used to find properties |
|
* defined in superclasses of a Node. |
|
*/ |
|
public Optional<BaseNodeMetaModel> getSuperNodeMetaModel() { |
|
return superNodeMetaModel; |
|
} |
|
/** |
|
* @return a list of all properties declared directly in this node (not its parent nodes.) These are also available |
|
* as fields. |
|
*/ |
|
public List<PropertyMetaModel> getDeclaredPropertyMetaModels() { |
|
return declaredPropertyMetaModels; |
|
} |
|
public List<PropertyMetaModel> getDerivedPropertyMetaModels() { |
|
return derivedPropertyMetaModels; |
|
} |
|
/** |
|
* @return a list of all properties that describe the parameters to the all-fields (but not "range" and "comment") |
|
* constructor, in the order of appearance in the constructor parameter list. |
|
*/ |
|
public List<PropertyMetaModel> getConstructorParameters() { |
|
return constructorParameters; |
|
} |
|
/** |
|
* @return a list of all properties in this node and its parents. Note that a new list is created every time this |
|
* method is called. |
|
*/ |
|
public List<PropertyMetaModel> getAllPropertyMetaModels() { |
|
List<PropertyMetaModel> allPropertyMetaModels = new ArrayList<>(getDeclaredPropertyMetaModels()); |
|
BaseNodeMetaModel walkNode = this; |
|
while (walkNode.getSuperNodeMetaModel().isPresent()) { |
|
walkNode = walkNode.getSuperNodeMetaModel().get(); |
|
allPropertyMetaModels.addAll(walkNode.getDeclaredPropertyMetaModels()); |
|
} |
|
return allPropertyMetaModels; |
|
} |
|
public boolean isInstanceOfMetaModel(BaseNodeMetaModel baseMetaModel) { |
|
if (this == baseMetaModel) { |
|
return true; |
|
} |
|
if (isRootNode()) { |
|
return false; |
|
} |
|
return getSuperNodeMetaModel().get().isInstanceOfMetaModel(baseMetaModel); |
|
} |
|
/** |
|
* @return the class for this AST node type. |
|
*/ |
|
public Class<? extends Node> getType() { |
|
return type; |
|
} |
|
/** |
|
* @return the package containing this AST node class. |
|
*/ |
|
public String getPackageName() { |
|
return packageName; |
|
} |
|
/** |
|
* @return whether this AST node is abstract. |
|
*/ |
|
public boolean isAbstract() { |
|
return isAbstract; |
|
} |
|
/** |
|
* @return whether this AST node has a <?> at the end of its type. |
|
*/ |
|
public boolean hasWildcard() { |
|
return hasWildcard; |
|
} |
|
/** |
|
* @return whether this AST node is the root node, meaning that it is the meta model for "Node": "NodeMetaModel". |
|
*/ |
|
public boolean isRootNode() { |
|
return !superNodeMetaModel.isPresent(); |
|
} |
|
@Override |
|
public boolean equals(Object o) { |
|
if (this == o) return true; |
|
if (o == null || getClass() != o.getClass()) return false; |
|
BaseNodeMetaModel classMetaModel = (BaseNodeMetaModel) o; |
|
if (!type.equals(classMetaModel.type)) return false; |
|
return true; |
|
} |
|
@Override |
|
public int hashCode() { |
|
return type.hashCode(); |
|
} |
|
@Override |
|
public String toString() { |
|
return name; |
|
} |
|
/** |
|
* @return the type name, with generics. |
|
*/ |
|
public String getTypeNameGenerified() { |
|
if (hasWildcard) { |
|
return getTypeName() + "<?>"; |
|
} |
|
return getTypeName(); |
|
} |
|
/** |
|
* @return the raw type name, so nothing but the name. |
|
*/ |
|
public String getTypeName() { |
|
return type.getSimpleName(); |
|
} |
|
/** |
|
* The name of the field in JavaParserMetaModel for this node meta model. |
|
*/ |
|
public String getMetaModelFieldName() { |
|
return decapitalize(getClass().getSimpleName()); |
|
} |
|
/** |
|
* Creates a new node of this type. |
|
* |
|
* @param parameters a map of propertyName -> value. |
|
* This should at least contain a pair for every required property for this node. |
|
*/ |
|
public Node construct(Map<String, Object> parameters) { |
|
for (Constructor<?> constructor : getType().getConstructors()) { |
|
if (constructor.getAnnotation(AllFieldsConstructor.class) != null) { |
|
try { |
|
Object[] paramArray = new Object[constructor.getParameterCount()]; |
|
int i = 0; |
|
for (PropertyMetaModel constructorParameter : getConstructorParameters()) { |
|
paramArray[i] = parameters.get(constructorParameter.getName()); |
|
if (paramArray[i] == null && constructorParameter.isRequired()) { |
|
if (constructorParameter.isNodeList()) { |
|
paramArray[i] = new NodeList<>(); |
|
} |
|
// We could have more defaults here. |
|
} |
|
i++; |
|
} |
|
return (Node) constructor.newInstance(paramArray); |
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
} |
|
throw new IllegalStateException(); |
|
} |
|
} |