1 package com.github.javaparser.metamodel; 2 3 import com.github.javaparser.ast.AllFieldsConstructor; 4 import com.github.javaparser.ast.Node; 5 import com.github.javaparser.ast.NodeList; 6 7 import java.lang.reflect.Constructor; 8 import java.lang.reflect.InvocationTargetException; 9 import java.util.*; 10 11 import static com.github.javaparser.utils.Utils.decapitalize; 12 13 /** 14 * Meta-data about all classes in the AST. These are all Nodes, except NodeList. 15 */ 16 public abstract class BaseNodeMetaModel { 17 private final Optional<BaseNodeMetaModel> superNodeMetaModel; 18 private final List<PropertyMetaModel> declaredPropertyMetaModels = new ArrayList<>(); 19 private final List<PropertyMetaModel> derivedPropertyMetaModels = new ArrayList<>(); 20 private final List<PropertyMetaModel> constructorParameters = new ArrayList<>(); 21 private final Class<? extends Node> type; 22 private final String name; 23 private final String packageName; 24 private final boolean isAbstract; 25 private final boolean hasWildcard; 26 BaseNodeMetaModel(Optional<BaseNodeMetaModel> superNodeMetaModel, Class<? extends Node> type, String name, String packageName, boolean isAbstract, boolean hasWildcard)27 public BaseNodeMetaModel(Optional<BaseNodeMetaModel> superNodeMetaModel, Class<? extends Node> type, String name, String packageName, boolean isAbstract, boolean hasWildcard) { 28 this.superNodeMetaModel = superNodeMetaModel; 29 this.type = type; 30 this.name = name; 31 this.packageName = packageName; 32 this.isAbstract = isAbstract; 33 this.hasWildcard = hasWildcard; 34 } 35 36 /** 37 * @return is this the meta model for this node class? 38 */ is(Class<? extends Node> c)39 public boolean is(Class<? extends Node> c) { 40 return type.equals(c); 41 } 42 43 /** 44 * @return package name + class name 45 */ getQualifiedClassName()46 public String getQualifiedClassName() { 47 return packageName + "." + name; 48 } 49 50 /** 51 * @return the meta model for the node that this node extends. Note that this is to be used to find properties 52 * defined in superclasses of a Node. 53 */ getSuperNodeMetaModel()54 public Optional<BaseNodeMetaModel> getSuperNodeMetaModel() { 55 return superNodeMetaModel; 56 } 57 58 /** 59 * @return a list of all properties declared directly in this node (not its parent nodes.) These are also available 60 * as fields. 61 */ getDeclaredPropertyMetaModels()62 public List<PropertyMetaModel> getDeclaredPropertyMetaModels() { 63 return declaredPropertyMetaModels; 64 } 65 getDerivedPropertyMetaModels()66 public List<PropertyMetaModel> getDerivedPropertyMetaModels() { 67 return derivedPropertyMetaModels; 68 } 69 70 /** 71 * @return a list of all properties that describe the parameters to the all-fields (but not "range" and "comment") 72 * constructor, in the order of appearance in the constructor parameter list. 73 */ getConstructorParameters()74 public List<PropertyMetaModel> getConstructorParameters() { 75 return constructorParameters; 76 } 77 78 /** 79 * @return a list of all properties in this node and its parents. Note that a new list is created every time this 80 * method is called. 81 */ getAllPropertyMetaModels()82 public List<PropertyMetaModel> getAllPropertyMetaModels() { 83 List<PropertyMetaModel> allPropertyMetaModels = new ArrayList<>(getDeclaredPropertyMetaModels()); 84 BaseNodeMetaModel walkNode = this; 85 while (walkNode.getSuperNodeMetaModel().isPresent()) { 86 walkNode = walkNode.getSuperNodeMetaModel().get(); 87 allPropertyMetaModels.addAll(walkNode.getDeclaredPropertyMetaModels()); 88 } 89 return allPropertyMetaModels; 90 } 91 isInstanceOfMetaModel(BaseNodeMetaModel baseMetaModel)92 public boolean isInstanceOfMetaModel(BaseNodeMetaModel baseMetaModel) { 93 if (this == baseMetaModel) { 94 return true; 95 } 96 if (isRootNode()) { 97 return false; 98 } 99 return getSuperNodeMetaModel().get().isInstanceOfMetaModel(baseMetaModel); 100 } 101 102 /** 103 * @return the class for this AST node type. 104 */ getType()105 public Class<? extends Node> getType() { 106 return type; 107 } 108 109 /** 110 * @return the package containing this AST node class. 111 */ getPackageName()112 public String getPackageName() { 113 return packageName; 114 } 115 116 /** 117 * @return whether this AST node is abstract. 118 */ isAbstract()119 public boolean isAbstract() { 120 return isAbstract; 121 } 122 123 /** 124 * @return whether this AST node has a <?> at the end of its type. 125 */ hasWildcard()126 public boolean hasWildcard() { 127 return hasWildcard; 128 } 129 130 /** 131 * @return whether this AST node is the root node, meaning that it is the meta model for "Node": "NodeMetaModel". 132 */ isRootNode()133 public boolean isRootNode() { 134 return !superNodeMetaModel.isPresent(); 135 } 136 137 @Override equals(Object o)138 public boolean equals(Object o) { 139 if (this == o) return true; 140 if (o == null || getClass() != o.getClass()) return false; 141 142 BaseNodeMetaModel classMetaModel = (BaseNodeMetaModel) o; 143 144 if (!type.equals(classMetaModel.type)) return false; 145 146 return true; 147 } 148 149 @Override hashCode()150 public int hashCode() { 151 return type.hashCode(); 152 } 153 154 @Override toString()155 public String toString() { 156 return name; 157 } 158 159 /** 160 * @return the type name, with generics. 161 */ getTypeNameGenerified()162 public String getTypeNameGenerified() { 163 if (hasWildcard) { 164 return getTypeName() + "<?>"; 165 } 166 return getTypeName(); 167 } 168 169 /** 170 * @return the raw type name, so nothing but the name. 171 */ getTypeName()172 public String getTypeName() { 173 return type.getSimpleName(); 174 } 175 176 /** 177 * The name of the field in JavaParserMetaModel for this node meta model. 178 */ getMetaModelFieldName()179 public String getMetaModelFieldName() { 180 return decapitalize(getClass().getSimpleName()); 181 } 182 183 /** 184 * Creates a new node of this type. 185 * 186 * @param parameters a map of propertyName -> value. 187 * This should at least contain a pair for every required property for this node. 188 */ construct(Map<String, Object> parameters)189 public Node construct(Map<String, Object> parameters) { 190 for (Constructor<?> constructor : getType().getConstructors()) { 191 if (constructor.getAnnotation(AllFieldsConstructor.class) != null) { 192 try { 193 Object[] paramArray = new Object[constructor.getParameterCount()]; 194 int i = 0; 195 for (PropertyMetaModel constructorParameter : getConstructorParameters()) { 196 paramArray[i] = parameters.get(constructorParameter.getName()); 197 if (paramArray[i] == null && constructorParameter.isRequired()) { 198 if (constructorParameter.isNodeList()) { 199 paramArray[i] = new NodeList<>(); 200 } 201 // We could have more defaults here. 202 } 203 i++; 204 } 205 return (Node) constructor.newInstance(paramArray); 206 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { 207 throw new RuntimeException(e); 208 } 209 } 210 } 211 throw new IllegalStateException(); 212 } 213 } 214