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