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.logic.AbstractTypeDeclaration;
     28 import com.github.javaparser.symbolsolver.logic.ConfilictingGenericTypesException;
     29 import com.github.javaparser.symbolsolver.logic.InferenceContext;
     30 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
     31 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
     32 import com.github.javaparser.symbolsolver.model.typesystem.NullType;
     33 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
     34 
     35 import java.lang.reflect.Field;
     36 import java.util.*;
     37 import java.util.stream.Collectors;
     38 
     39 /**
     40  * @author Federico Tomassetti
     41  */
     42 public class ReflectionInterfaceDeclaration extends AbstractTypeDeclaration implements ResolvedInterfaceDeclaration {
     43 
     44     ///
     45     /// Fields
     46     ///
     47 
     48     private Class<?> clazz;
     49     private TypeSolver typeSolver;
     50     private ReflectionClassAdapter reflectionClassAdapter;
     51 
     52     ///
     53     /// Constructor
     54     ///
     55 
     56     public ReflectionInterfaceDeclaration(Class<?> clazz, TypeSolver typeSolver) {
     57         if (!clazz.isInterface()) {
     58             throw new IllegalArgumentException();
     59         }
     60 
     61         this.clazz = clazz;
     62         this.typeSolver = typeSolver;
     63         this.reflectionClassAdapter = new ReflectionClassAdapter(clazz, typeSolver, this);
     64     }
     65 
     66     ///
     67     /// Public methods
     68     ///
     69 
     70     @Override
     71     public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) {
     72         return isAssignableBy(new ReferenceTypeImpl(other, typeSolver));
     73     }
     74 
     75     @Override
     76     public String getPackageName() {
     77         if (clazz.getPackage() != null) {
     78             return clazz.getPackage().getName();
     79         }
     80         return null;
     81     }
     82 
     83     @Override
     84     public String getClassName() {
     85         String canonicalName = clazz.getCanonicalName();
     86         if (canonicalName != null && getPackageName() != null) {
     87             return canonicalName.substring(getPackageName().length() + 1, canonicalName.length());
     88         }
     89         return null;
     90     }
     91 
     92     @Override
     93     public String getQualifiedName() {
     94         return clazz.getCanonicalName();
     95     }
     96 
     97     @Deprecated
     98     public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes, boolean staticOnly) {
     99         return ReflectionMethodResolutionLogic.solveMethod(name, parameterTypes, staticOnly,
    100                 typeSolver,this, clazz);
    101     }
    102 
    103     @Override
    104     public String toString() {
    105         return "ReflectionInterfaceDeclaration{" +
    106                 "clazz=" + clazz.getCanonicalName() +
    107                 '}';
    108     }
    109 
    110     public ResolvedType getUsage(Node node) {
    111         return new ReferenceTypeImpl(this, typeSolver);
    112     }
    113 
    114     @Override
    115     public boolean equals(Object o) {
    116         if (this == o) return true;
    117         if (!(o instanceof ReflectionInterfaceDeclaration)) return false;
    118 
    119         ReflectionInterfaceDeclaration that = (ReflectionInterfaceDeclaration) o;
    120 
    121         if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false;
    122 
    123         if (!getTypeParameters().equals(that.getTypeParameters())) {
    124             return false;
    125         }
    126 
    127         return true;
    128     }
    129 
    130     @Override
    131     public int hashCode() {
    132         return clazz.hashCode();
    133     }
    134 
    135     public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> parameterTypes, TypeSolver typeSolver,
    136                                                     Context invokationContext, List<ResolvedType> typeParameterValues) {
    137         Optional<MethodUsage> res = ReflectionMethodResolutionLogic.solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext,
    138                 typeParameterValues, this, clazz);
    139         if (res.isPresent()) {
    140             // We have to replace method type typeParametersValues here
    141             InferenceContext inferenceContext = new InferenceContext(MyObjectProvider.INSTANCE);
    142             MethodUsage methodUsage = res.get();
    143             int i = 0;
    144             List<ResolvedType> parameters = new LinkedList<>();
    145             for (ResolvedType actualType : parameterTypes) {
    146                 ResolvedType formalType = methodUsage.getParamType(i);
    147                 // We need to replace the class type typeParametersValues (while we derive the method ones)
    148 
    149                 parameters.add(inferenceContext.addPair(formalType, actualType));
    150                 i++;
    151             }
    152             try {
    153                 ResolvedType returnType = inferenceContext.addSingle(methodUsage.returnType());
    154                 for (int j=0;j<parameters.size();j++) {
    155                     methodUsage = methodUsage.replaceParamType(j, inferenceContext.resolve(parameters.get(j)));
    156                 }
    157                 methodUsage = methodUsage.replaceReturnType(inferenceContext.resolve(returnType));
    158                 return Optional.of(methodUsage);
    159             } catch (ConfilictingGenericTypesException e) {
    160                 return Optional.empty();
    161             }
    162         } else {
    163             return res;
    164         }
    165     }
    166 
    167     @Override
    168     public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) {
    169         if (other instanceof LambdaArgumentTypePlaceholder) {
    170             return isFunctionalInterface();
    171         }
    172         if (other.getQualifiedName().equals(getQualifiedName())) {
    173             return true;
    174         }
    175         if (this.clazz.getSuperclass() != null
    176                 && new ReflectionInterfaceDeclaration(clazz.getSuperclass(), typeSolver).canBeAssignedTo(other)) {
    177             return true;
    178         }
    179         for (Class interfaze : clazz.getInterfaces()) {
    180             if (new ReflectionInterfaceDeclaration(interfaze, typeSolver).canBeAssignedTo(other)) {
    181                 return true;
    182             }
    183         }
    184 
    185         if (other.getQualifiedName().equals(Object.class.getCanonicalName())) {
    186             return true;
    187         }
    188 
    189         return false;
    190     }
    191 
    192     @Override
    193     public boolean isAssignableBy(ResolvedType type) {
    194         if (type instanceof NullType) {
    195             return true;
    196         }
    197         if (type instanceof LambdaArgumentTypePlaceholder) {
    198             return isFunctionalInterface();
    199         }
    200         if (type.isArray()) {
    201             return false;
    202         }
    203         if (type.isPrimitive()) {
    204             return false;
    205         }
    206         if (type.describe().equals(getQualifiedName())) {
    207             return true;
    208         }
    209         if (type instanceof ReferenceTypeImpl) {
    210             ReferenceTypeImpl otherTypeDeclaration = (ReferenceTypeImpl) type;
    211             return otherTypeDeclaration.getTypeDeclaration().canBeAssignedTo(this);
    212         }
    213 
    214         return false;
    215     }
    216 
    217     @Override
    218     public boolean isTypeParameter() {
    219         return false;
    220     }
    221 
    222     @Override
    223     public ResolvedFieldDeclaration getField(String name) {
    224         return reflectionClassAdapter.getField(name);
    225     }
    226 
    227     @Override
    228     public List<ResolvedFieldDeclaration> getAllFields() {
    229         return reflectionClassAdapter.getAllFields();
    230     }
    231 
    232     @Deprecated
    233     public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
    234         for (Field field : clazz.getFields()) {
    235             if (field.getName().equals(name)) {
    236                 return SymbolReference.solved(new ReflectionFieldDeclaration(field, typeSolver));
    237             }
    238         }
    239         return SymbolReference.unsolved(ResolvedValueDeclaration.class);
    240     }
    241 
    242     @Override
    243     public List<ResolvedReferenceType> getAncestors() {
    244         return reflectionClassAdapter.getAncestors();
    245     }
    246 
    247     @Override
    248     public Set<ResolvedMethodDeclaration> getDeclaredMethods() {
    249         return reflectionClassAdapter.getDeclaredMethods();
    250     }
    251 
    252     @Override
    253     public boolean hasField(String name) {
    254         return reflectionClassAdapter.hasField(name);
    255     }
    256 
    257     @Override
    258     public String getName() {
    259         return clazz.getSimpleName();
    260     }
    261 
    262     @Override
    263     public boolean isInterface() {
    264         return true;
    265     }
    266 
    267     @Override
    268     public List<ResolvedReferenceType> getInterfacesExtended() {
    269         List<ResolvedReferenceType> res = new ArrayList<>();
    270         for (Class i : clazz.getInterfaces()) {
    271             res.add(new ReferenceTypeImpl(new ReflectionInterfaceDeclaration(i, typeSolver), typeSolver));
    272         }
    273         return res;
    274     }
    275 
    276     @Override
    277     public Optional<ResolvedReferenceTypeDeclaration> containerType() {
    278         return reflectionClassAdapter.containerType();
    279     }
    280 
    281     @Override
    282     public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
    283         return Arrays.stream(this.clazz.getDeclaredClasses())
    284                 .map(ic -> ReflectionFactory.typeDeclarationFor(ic, typeSolver))
    285                 .collect(Collectors.toSet());
    286     }
    287 
    288     @Override
    289     public ResolvedInterfaceDeclaration asInterface() {
    290         return this;
    291     }
    292 
    293     @Override
    294     public boolean hasDirectlyAnnotation(String canonicalName) {
    295         return reflectionClassAdapter.hasDirectlyAnnotation(canonicalName);
    296     }
    297 
    298     @Override
    299     public List<ResolvedTypeParameterDeclaration> getTypeParameters() {
    300         return reflectionClassAdapter.getTypeParameters();
    301     }
    302 
    303     @Override
    304     public AccessSpecifier accessSpecifier() {
    305         return ReflectionFactory.modifiersToAccessLevel(this.clazz.getModifiers());
    306     }
    307 }
    308