• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.github.javaparser.symbolsolver.model.declarations;
2 
3 import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
4 import com.github.javaparser.symbolsolver.model.resolution.UnsolvedSymbolException;
5 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceType;
6 import com.github.javaparser.symbolsolver.model.typesystem.Type;
7 
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.Optional;
11 import java.util.Set;
12 import java.util.stream.Collectors;
13 
14 /**
15  * @author Federico Tomassetti
16  */
17 public interface ReferenceTypeDeclaration extends TypeDeclaration, TypeParametrizable {
18 
19     @Override
asReferenceType()20     default ReferenceTypeDeclaration asReferenceType() {
21         return this;
22     }
23 
24     ///
25     /// Ancestors
26     ///
27 
28     /**
29      * The list of all the direct ancestors of the current declaration.
30      * Note that the ancestor can be parametrized types with values specified. For example:
31      * <p>
32      * class A implements Comparable&lt;String&gt; {}
33      * <p>
34      * In this case the ancestor is Comparable&lt;String&gt;
35      */
getAncestors()36     List<ReferenceType> getAncestors();
37 
38     /**
39      * The list of all the ancestors of the current declaration, direct and indirect.
40      * This list does not contains duplicates with the exacting same type parameters.
41      */
getAllAncestors()42     default List<ReferenceType> getAllAncestors() {
43         List<ReferenceType> ancestors = new ArrayList<>();
44         // We want to avoid infinite recursion in case of Object having Object as ancestor
45         if (!(Object.class.getCanonicalName().equals(getQualifiedName()))) {
46             for (ReferenceType ancestor : getAncestors()) {
47                 ancestors.add(ancestor);
48                 for (ReferenceType inheritedAncestor : ancestor.getAllAncestors()) {
49                     if (!ancestors.contains(inheritedAncestor)) {
50                         ancestors.add(inheritedAncestor);
51                     }
52                 }
53             }
54         }
55         return ancestors;
56     }
57 
58     ///
59     /// Fields
60     ///
61 
62     /**
63      * Note that the type of the field should be expressed using the type variables of this particular type.
64      * Consider for example:
65      * <p>
66      * class Foo<E> { E field; }
67      * <p>
68      * class Bar extends Foo<String> { }
69      * <p>
70      * When calling getField("field") on Foo I should get a FieldDeclaration with type E, while calling it on
71      * Bar I should get a FieldDeclaration with type String.
72      */
getField(String name)73     default FieldDeclaration getField(String name) {
74         Optional<FieldDeclaration> field = this.getAllFields().stream().filter(f -> f.getName().equals(name)).findFirst();
75         if (field.isPresent()) {
76             return field.get();
77         } else {
78             throw new UnsolvedSymbolException("Field not found: " + name);
79         }
80     }
81 
82     /**
83      * Consider only field or inherited field which is not private.
84      */
getVisibleField(String name)85     default FieldDeclaration getVisibleField(String name) {
86         Optional<FieldDeclaration> field = getVisibleFields().stream().filter(f -> f.getName().equals(name)).findFirst();
87         if (field.isPresent()) {
88             return field.get();
89         } else {
90             throw new IllegalArgumentException();
91         }
92     }
93 
94     /**
95      * Has this type a field with the given name?
96      */
hasField(String name)97     default boolean hasField(String name) {
98         return this.getAllFields().stream().filter(f -> f.getName().equals(name)).findFirst().isPresent();
99     }
100 
101     /**
102      * Either a declared field or inherited field which is not private.
103      */
hasVisibleField(String name)104     default boolean hasVisibleField(String name) {
105         return getVisibleFields().stream().filter(f -> f.getName().equals(name)).findFirst().isPresent();
106     }
107 
108     /**
109      * Return a list of all fields, either declared in this declaration or inherited.
110      *
111      * Note that they could refer to inherited type variables.
112      */
getAllFields()113     List<FieldDeclaration> getAllFields();
114 
115     /**
116      * Return a list of all fields declared and the inherited ones which are not private.
117      */
getVisibleFields()118     default List<FieldDeclaration> getVisibleFields() {
119         return getAllFields().stream()
120                 .filter(f -> f.declaringType().equals(this) || f.accessLevel() != AccessLevel.PRIVATE)
121                 .collect(Collectors.toList());
122     }
123 
124     /**
125      * Return a list of all the non static fields, either declared or inherited.
126      */
getAllNonStaticFields()127     default List<FieldDeclaration> getAllNonStaticFields() {
128         return getAllFields().stream().filter(it -> !it.isStatic()).collect(Collectors.toList());
129     }
130 
131     /**
132      * Return a list of all the static fields, either declared or inherited.
133      */
getAllStaticFields()134     default List<FieldDeclaration> getAllStaticFields() {
135         return getAllFields().stream().filter(it -> it.isStatic()).collect(Collectors.toList());
136     }
137 
138     /**
139      * Return a list of all the fields declared in this type.
140      */
getDeclaredFields()141     default List<FieldDeclaration> getDeclaredFields() {
142         return getAllFields().stream().filter(it -> it.declaringType().getQualifiedName().equals(getQualifiedName())).collect(Collectors.toList());
143     }
144 
145     ///
146     /// Methods
147     ///
148 
149     /**
150      * Return a list of all the methods declared in this type declaration.
151      */
getDeclaredMethods()152     Set<MethodDeclaration> getDeclaredMethods();
153 
154     /**
155      * Return a list of all the methods declared of this type declaration, either declared or inherited.
156      * Note that it should not include overridden methods.
157      */
getAllMethods()158     Set<MethodUsage> getAllMethods();
159 
160     ///
161     /// Assignability
162     ///
163 
164     /**
165      * Can we assign instances of the given type to variables having the type defined
166      * by this declaration?
167      */
isAssignableBy(Type type)168     boolean isAssignableBy(Type type);
169 
170     /**
171      * Can we assign instances of the type defined by this declaration to variables having the type defined
172      * by the given type?
173      */
canBeAssignedTo(ReferenceTypeDeclaration other)174     default boolean canBeAssignedTo(ReferenceTypeDeclaration other) {
175         return other.isAssignableBy(this);
176     }
177 
178     /**
179      * Can we assign instances of the given type to variables having the type defined
180      * by this declaration?
181      */
isAssignableBy(ReferenceTypeDeclaration other)182     boolean isAssignableBy(ReferenceTypeDeclaration other);
183 
184     ///
185     /// Annotations
186     ///
187 
188     /**
189      * Has the type at least one annotation declared having the specified qualified name?
190      */
hasDirectlyAnnotation(String qualifiedName)191     boolean hasDirectlyAnnotation(String qualifiedName);
192 
193     /**
194      * Has the type at least one annotation declared or inherited having the specified qualified name?
195      */
hasAnnotation(String qualifiedName)196     default boolean hasAnnotation(String qualifiedName) {
197         if (hasDirectlyAnnotation(qualifiedName)) {
198             return true;
199         }
200         return getAllAncestors().stream().anyMatch(it -> it.asReferenceType().getTypeDeclaration().hasDirectlyAnnotation(qualifiedName));
201     }
202 
203     /**
204      * This means that the type has a functional method. Conceptually, a functional interface has exactly one abstract method.
205      * Typically these classes has the FunctionInterface annotation but this is not mandatory.
206      */
isFunctionalInterface()207     boolean isFunctionalInterface();
208 
209     ///
210     /// Type parameters
211     ///
212 
213     @Override
findTypeParameter(String name)214     default Optional<TypeParameterDeclaration> findTypeParameter(String name) {
215         for (TypeParameterDeclaration tp : this.getTypeParameters()) {
216             if (tp.getName().equals(name)) {
217                 return Optional.of(tp);
218             }
219         }
220         if (this.containerType().isPresent()) {
221             return this.containerType().get().findTypeParameter(name);
222         }
223         return Optional.empty();
224     }
225 }
226