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