Home | History | Annotate | Download | only in metamodel
      1 package com.github.javaparser.metamodel;
      2 
      3 import com.github.javaparser.ast.Node;
      4 
      5 import java.lang.reflect.Field;
      6 import java.util.Optional;
      7 
      8 import static com.github.javaparser.utils.CodeGenerationUtils.getterName;
      9 import static com.github.javaparser.utils.CodeGenerationUtils.setterName;
     10 
     11 /**
     12  * Meta-data about a property of a node in the AST.
     13  */
     14 public class PropertyMetaModel {
     15     private final BaseNodeMetaModel containingNodeMetaModel;
     16     private final String name;
     17     private final Class<?> type;
     18     private final Optional<BaseNodeMetaModel> nodeReference;
     19     private final boolean isOptional;
     20     private final boolean isNonEmpty;
     21     private final boolean isNodeList;
     22     private final boolean isEnumSet;
     23     private final boolean hasWildcard;
     24 
     25     public PropertyMetaModel(BaseNodeMetaModel containingNodeMetaModel, String name, Class<?> type, Optional<BaseNodeMetaModel> nodeReference, boolean isOptional, boolean isNonEmpty, boolean isNodeList, boolean isEnumSet, boolean hasWildcard) {
     26         this.containingNodeMetaModel = containingNodeMetaModel;
     27         this.name = name;
     28         this.type = type;
     29         this.nodeReference = nodeReference;
     30         this.isOptional = isOptional;
     31         this.isNonEmpty = isNonEmpty;
     32         this.isNodeList = isNodeList;
     33         this.isEnumSet = isEnumSet;
     34         this.hasWildcard = hasWildcard;
     35     }
     36 
     37     /**
     38      * @return is this the field fieldName on class c?
     39      */
     40     public boolean is(Class<? extends Node> c, String fieldName) {
     41         return containingNodeMetaModel.is(c) && name.equals(fieldName);
     42     }
     43 
     44     /**
     45      * @return is this fields called fieldName?
     46      */
     47     public boolean is(String fieldName) {
     48         return name.equals(fieldName);
     49     }
     50 
     51     /**
     52      * @return the name used in the AST for the setter
     53      */
     54     public String getSetterMethodName() {
     55         return setterName(name);
     56     }
     57 
     58     /**
     59      * @return the name used in the AST for the getter
     60      */
     61     public String getGetterMethodName() {
     62         return getterName(type, name);
     63     }
     64 
     65     /**
     66      * @return the NodeMetaModel that "has" this property.
     67      */
     68     public BaseNodeMetaModel getContainingNodeMetaModel() {
     69         return containingNodeMetaModel;
     70     }
     71 
     72     /**
     73      * @return the name of the property. This is equal to the name of the field in the AST.
     74      */
     75     public String getName() {
     76         return name;
     77     }
     78 
     79     /**
     80      * @return if this property is a String or a NodeList: whether it may be empty.
     81      */
     82     public boolean isNonEmpty() {
     83         return isNonEmpty;
     84     }
     85 
     86     /**
     87      * @return the class of the field.
     88      */
     89     public Class<?> getType() {
     90         return type;
     91     }
     92 
     93     /**
     94      * @return if this property is a Node, this will get the node meta model.
     95      */
     96     public Optional<BaseNodeMetaModel> getNodeReference() {
     97         return nodeReference;
     98     }
     99 
    100     /**
    101      * @return whether this property is optional.
    102      */
    103     public boolean isOptional() {
    104         return isOptional;
    105     }
    106 
    107     /**
    108      * @return whether this property is not optional.
    109      */
    110     public boolean isRequired() {
    111         return !isOptional;
    112     }
    113 
    114     /**
    115      * @return whether this property is contained in a NodeList.
    116      */
    117     public boolean isNodeList() {
    118         return isNodeList;
    119     }
    120 
    121     /**
    122      * @return whether this property is contained in an EnumSet.
    123      */
    124     public boolean isEnumSet() {
    125         return isEnumSet;
    126     }
    127 
    128     /**
    129      * @return whether this property has a wildcard following it, like BodyDeclaration&lt;?&gt;.
    130      */
    131     public boolean hasWildcard() {
    132         return hasWildcard;
    133     }
    134 
    135     /**
    136      * @return whether this property is not a list or set.
    137      */
    138     public boolean isSingular() {
    139         return !(isNodeList || isEnumSet);
    140     }
    141 
    142     @Override
    143     public String toString() {
    144         return "(" + getTypeName() + ")\t" + containingNodeMetaModel + "#" + name;
    145     }
    146 
    147     @Override
    148     public boolean equals(Object o) {
    149         if (this == o) return true;
    150         if (o == null || getClass() != o.getClass()) return false;
    151 
    152         PropertyMetaModel that = (PropertyMetaModel) o;
    153 
    154         if (!name.equals(that.name)) return false;
    155         if (!type.equals(that.type)) return false;
    156 
    157         return true;
    158     }
    159 
    160     @Override
    161     public int hashCode() {
    162         int result = name.hashCode();
    163         result = 31 * result + type.hashCode();
    164         return result;
    165     }
    166 
    167     /**
    168      * @return the type of a single element of this property, so no Optional or NodeList or EnumSet.
    169      */
    170     public String getTypeNameGenerified() {
    171         if (hasWildcard) {
    172             return getTypeName() + "<?>";
    173         }
    174         return getTypeName();
    175     }
    176 
    177     /**
    178      * @return the raw type of a single element of this property, so nothing but the name.
    179      */
    180     public String getTypeName() {
    181         return type.getSimpleName();
    182     }
    183 
    184     /**
    185      * @return the type that is returned from getters in the AST.
    186      */
    187     public String getTypeNameForGetter() {
    188         if (isOptional) {
    189             return "Optional<" + getTypeNameForSetter() + ">";
    190         }
    191         return getTypeNameForSetter();
    192     }
    193 
    194     /**
    195      * @return the type that is passed to setters in the AST.
    196      */
    197     public String getTypeNameForSetter() {
    198         if (isNodeList) {
    199             return "NodeList<" + getTypeNameGenerified() + ">";
    200         }
    201         if (isEnumSet) {
    202             return "EnumSet<" + getTypeNameGenerified() + ">";
    203         }
    204         return getTypeNameGenerified();
    205     }
    206 
    207     /**
    208      * @return is this property an AST Node?
    209      */
    210     public boolean isNode() {
    211         return getNodeReference().isPresent();
    212     }
    213 
    214     /**
    215      * The name of the field in the containing BaseNodeMetaModel for this property meta model.
    216      */
    217     public String getMetaModelFieldName() {
    218         return getName() + "PropertyMetaModel";
    219     }
    220 
    221     /**
    222      * @return is this property an attribute, meaning: not a node?
    223      */
    224     public boolean isAttribute() {
    225         return !isNode();
    226     }
    227 
    228     /**
    229      * Introspects the node to get the value from this field.
    230      * Note that an optional empty field will return null here.
    231      */
    232     public Object getValue(Node node) {
    233         try {
    234             for (Class<?> c = node.getClass(); c != null; c = c.getSuperclass()) {
    235                 Field[] fields = c.getDeclaredFields();
    236                 for (Field classField : fields) {
    237                     if (classField.getName().equals(getName())) {
    238                         classField.setAccessible(true);
    239                         return classField.get(node);
    240                     }
    241                 }
    242             }
    243             throw new NoSuchFieldError(getName());
    244         } catch (IllegalAccessException e) {
    245             throw new RuntimeException(e);
    246         }
    247     }
    248 }
    249