Home | History | Annotate | Download | only in reflectionmodel
      1 /*
      2  * Copyright 2016 Federico Tomassetti
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.github.javaparser.symbolsolver.reflectionmodel;
     18 
     19 import com.github.javaparser.ast.AccessSpecifier;
     20 import com.github.javaparser.ast.Node;
     21 import com.github.javaparser.resolution.MethodUsage;
     22 import com.github.javaparser.resolution.declarations.*;
     23 import com.github.javaparser.resolution.types.ResolvedReferenceType;
     24 import com.github.javaparser.resolution.types.ResolvedType;
     25 import com.github.javaparser.symbolsolver.core.resolution.Context;
     26 import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
     27 import com.github.javaparser.symbolsolver.javaparsermodel.contexts.ContextHelper;
     28 import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration;
     29 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
     30 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
     31 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
     32 import com.github.javaparser.symbolsolver.reflectionmodel.comparators.MethodComparator;
     33 import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
     34 
     35 import java.lang.reflect.Field;
     36 import java.lang.reflect.Method;
     37 import java.lang.reflect.Modifier;
     38 import java.util.*;
     39 import java.util.function.Predicate;
     40 import java.util.stream.Collectors;
     41 
     42 /**
     43  * @author Federico Tomassetti
     44  */
     45 public class ReflectionClassDeclaration extends AbstractClassDeclaration {
     46 
     47     ///
     48     /// Fields
     49     ///
     50 
     51     private Class<?> clazz;
     52     private TypeSolver typeSolver;
     53     private ReflectionClassAdapter reflectionClassAdapter;
     54 
     55     ///
     56     /// Constructors
     57     ///
     58 
     59     public ReflectionClassDeclaration(Class<?> clazz, TypeSolver typeSolver) {
     60         if (clazz == null) {
     61             throw new IllegalArgumentException("Class should not be null");
     62         }
     63         if (clazz.isInterface()) {
     64             throw new IllegalArgumentException("Class should not be an interface");
     65         }
     66         if (clazz.isPrimitive()) {
     67             throw new IllegalArgumentException("Class should not represent a primitive class");
     68         }
     69         if (clazz.isArray()) {
     70             throw new IllegalArgumentException("Class should not be an array");
     71         }
     72         if (clazz.isEnum()) {
     73             throw new IllegalArgumentException("Class should not be an enum");
     74         }
     75         this.clazz = clazz;
     76         this.typeSolver = typeSolver;
     77         this.reflectionClassAdapter = new ReflectionClassAdapter(clazz, typeSolver, this);
     78     }
     79 
     80     ///
     81     /// Public methods
     82     ///
     83 
     84     @Override
     85     public Set<ResolvedMethodDeclaration> getDeclaredMethods() {
     86         return reflectionClassAdapter.getDeclaredMethods();
     87     }
     88 
     89     @Override
     90     public List<ResolvedReferenceType> getAncestors() {
     91         return reflectionClassAdapter.getAncestors();
     92     }
     93 
     94     @Override
     95     public boolean equals(Object o) {
     96         if (this == o) return true;
     97         if (o == null || getClass() != o.getClass()) return false;
     98 
     99         ReflectionClassDeclaration that = (ReflectionClassDeclaration) o;
    100 
    101         if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false;
    102 
    103         return true;
    104     }
    105 
    106     @Override
    107     public int hashCode() {
    108         return clazz.hashCode();
    109     }
    110 
    111 
    112     @Override
    113     public String getPackageName() {
    114         if (clazz.getPackage() != null) {
    115             return clazz.getPackage().getName();
    116         }
    117         return null;
    118     }
    119 
    120     @Override
    121     public String getClassName() {
    122         String canonicalName = clazz.getCanonicalName();
    123         if (canonicalName != null && getPackageName() != null) {
    124             return canonicalName.substring(getPackageName().length() + 1, canonicalName.length());
    125         }
    126         return null;
    127     }
    128 
    129     @Override
    130     public String getQualifiedName() {
    131         return clazz.getCanonicalName();
    132     }
    133 
    134     @Deprecated
    135     public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly) {
    136         List<ResolvedMethodDeclaration> methods = new ArrayList<>();
    137         Predicate<Method> staticFilter = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
    138         for (Method method : Arrays.stream(clazz.getDeclaredMethods()).filter((m) -> m.getName().equals(name)).filter(staticFilter)
    139                                     .sorted(new MethodComparator()).collect(Collectors.toList())) {
    140             if (method.isBridge() || method.isSynthetic()) continue;
    141             ResolvedMethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
    142             methods.add(methodDeclaration);
    143         }
    144         if (getSuperClass() != null) {
    145             ResolvedClassDeclaration superClass = (ResolvedClassDeclaration) getSuperClass().getTypeDeclaration();
    146             SymbolReference<ResolvedMethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(superClass, name, argumentsTypes, staticOnly, typeSolver);
    147             if (ref.isSolved()) {
    148                 methods.add(ref.getCorrespondingDeclaration());
    149             }
    150         }
    151         for (ResolvedReferenceType interfaceDeclaration : getInterfaces()) {
    152             SymbolReference<ResolvedMethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver);
    153             if (ref.isSolved()) {
    154                 methods.add(ref.getCorrespondingDeclaration());
    155             }
    156         }
    157         return MethodResolutionLogic.findMostApplicable(methods, name, argumentsTypes, typeSolver);
    158     }
    159 
    160     @Override
    161     public String toString() {
    162         return "ReflectionClassDeclaration{" +
    163                 "clazz=" + getId() +
    164                 '}';
    165     }
    166 
    167     public ResolvedType getUsage(Node node) {
    168 
    169         return new ReferenceTypeImpl(this, typeSolver);
    170     }
    171 
    172     public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver, Context invokationContext, List<ResolvedType> typeParameterValues) {
    173         List<MethodUsage> methods = new ArrayList<>();
    174         for (Method method : Arrays.stream(clazz.getDeclaredMethods()).filter((m) -> m.getName().equals(name)).sorted(new MethodComparator()).collect(Collectors.toList())) {
    175             if (method.isBridge() || method.isSynthetic()) continue;
    176             ResolvedMethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
    177             MethodUsage methodUsage = new MethodUsage(methodDeclaration);
    178             for (int i = 0; i < getTypeParameters().size() && i < typeParameterValues.size(); i++) {
    179                 ResolvedTypeParameterDeclaration tpToReplace = getTypeParameters().get(i);
    180                 ResolvedType newValue = typeParameterValues.get(i);
    181                 methodUsage = methodUsage.replaceTypeParameter(tpToReplace, newValue);
    182             }
    183             methods.add(methodUsage);
    184         }
    185         if (getSuperClass() != null) {
    186             ResolvedClassDeclaration superClass = (ResolvedClassDeclaration) getSuperClass().getTypeDeclaration();
    187             Optional<MethodUsage> ref = ContextHelper.solveMethodAsUsage(superClass, name, argumentsTypes, typeSolver, invokationContext, typeParameterValues);
    188             if (ref.isPresent()) {
    189                 methods.add(ref.get());
    190             }
    191         }
    192         for (ResolvedReferenceType interfaceDeclaration : getInterfaces()) {
    193             Optional<MethodUsage> ref = ContextHelper.solveMethodAsUsage(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, typeSolver, invokationContext, typeParameterValues);
    194             if (ref.isPresent()) {
    195                 methods.add(ref.get());
    196             }
    197         }
    198         Optional<MethodUsage> ref = MethodResolutionLogic.findMostApplicableUsage(methods, name, argumentsTypes, typeSolver);
    199         return ref;
    200     }
    201 
    202     @Override
    203     public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) {
    204         if (other instanceof LambdaArgumentTypePlaceholder) {
    205             return isFunctionalInterface();
    206         }
    207         if (other.getQualifiedName().equals(getQualifiedName())) {
    208             return true;
    209         }
    210         if (this.clazz.getSuperclass() != null
    211                 && new ReflectionClassDeclaration(clazz.getSuperclass(), typeSolver).canBeAssignedTo(other)) {
    212             return true;
    213         }
    214         for (Class<?> interfaze : clazz.getInterfaces()) {
    215             if (new ReflectionInterfaceDeclaration(interfaze, typeSolver).canBeAssignedTo(other)) {
    216                 return true;
    217             }
    218         }
    219 
    220         return false;
    221     }
    222 
    223     @Override
    224     public boolean isAssignableBy(ResolvedType type) {
    225         return reflectionClassAdapter.isAssignableBy(type);
    226     }
    227 
    228     @Override
    229     public boolean isTypeParameter() {
    230         return false;
    231     }
    232 
    233     @Override
    234     public ResolvedFieldDeclaration getField(String name) {
    235         return reflectionClassAdapter.getField(name);
    236     }
    237 
    238     @Override
    239     public List<ResolvedFieldDeclaration> getAllFields() {
    240         return reflectionClassAdapter.getAllFields();
    241     }
    242 
    243     @Deprecated
    244     public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
    245         for (Field field : clazz.getFields()) {
    246             if (field.getName().equals(name)) {
    247                 return SymbolReference.solved(new ReflectionFieldDeclaration(field, typeSolver));
    248             }
    249         }
    250         return SymbolReference.unsolved(ResolvedValueDeclaration.class);
    251     }
    252 
    253     @Override
    254     public boolean hasDirectlyAnnotation(String canonicalName) {
    255         return reflectionClassAdapter.hasDirectlyAnnotation(canonicalName);
    256     }
    257 
    258     @Override
    259     public boolean hasField(String name) {
    260         return reflectionClassAdapter.hasField(name);
    261     }
    262 
    263     @Override
    264     public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) {
    265         return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
    266     }
    267 
    268     @Override
    269     public String getName() {
    270         return clazz.getSimpleName();
    271     }
    272 
    273     @Override
    274     public boolean isField() {
    275         return false;
    276     }
    277 
    278     @Override
    279     public boolean isParameter() {
    280         return false;
    281     }
    282 
    283     @Override
    284     public boolean isType() {
    285         return true;
    286     }
    287 
    288     @Override
    289     public boolean isClass() {
    290         return !clazz.isInterface();
    291     }
    292 
    293     @Override
    294     public ReferenceTypeImpl getSuperClass() {
    295         return reflectionClassAdapter.getSuperClass();
    296     }
    297 
    298     @Override
    299     public List<ResolvedReferenceType> getInterfaces() {
    300         return reflectionClassAdapter.getInterfaces();
    301     }
    302 
    303     @Override
    304     public boolean isInterface() {
    305         return clazz.isInterface();
    306     }
    307 
    308     @Override
    309     public List<ResolvedTypeParameterDeclaration> getTypeParameters() {
    310         return reflectionClassAdapter.getTypeParameters();
    311     }
    312 
    313     @Override
    314     public AccessSpecifier accessSpecifier() {
    315         return ReflectionFactory.modifiersToAccessLevel(this.clazz.getModifiers());
    316     }
    317 
    318     @Override
    319     public List<ResolvedConstructorDeclaration> getConstructors() {
    320         return reflectionClassAdapter.getConstructors();
    321     }
    322 
    323     @Override
    324     public Optional<ResolvedReferenceTypeDeclaration> containerType() {
    325         return reflectionClassAdapter.containerType();
    326     }
    327 
    328     @Override
    329     public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
    330         return Arrays.stream(this.clazz.getDeclaredClasses())
    331                 .map(ic -> ReflectionFactory.typeDeclarationFor(ic, typeSolver))
    332                 .collect(Collectors.toSet());
    333     }
    334 
    335     ///
    336     /// Protected methods
    337     ///
    338 
    339     @Override
    340     protected ResolvedReferenceType object() {
    341         return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
    342     }
    343 
    344 }
    345