|
16 | 16 | package org.springframework.data.repository.aot.generate; |
17 | 17 |
|
18 | 18 | import java.lang.reflect.Method; |
19 | | -import java.lang.reflect.Type; |
20 | | -import java.lang.reflect.TypeVariable; |
21 | | -import java.lang.reflect.WildcardType; |
22 | 19 | import java.util.ArrayList; |
23 | 20 | import java.util.Arrays; |
24 | 21 | import java.util.Comparator; |
25 | | -import java.util.HashSet; |
26 | 22 | import java.util.List; |
27 | | -import java.util.Set; |
28 | 23 | import java.util.function.Consumer; |
29 | | -import java.util.function.Predicate; |
30 | 24 |
|
31 | 25 | import javax.lang.model.element.Modifier; |
32 | 26 |
|
33 | 27 | import org.apache.commons.logging.Log; |
34 | 28 | import org.apache.commons.logging.LogFactory; |
35 | 29 | import org.jspecify.annotations.Nullable; |
36 | | - |
37 | | -import org.springframework.core.ResolvableType; |
38 | 30 | import org.springframework.data.projection.ProjectionFactory; |
39 | 31 | import org.springframework.data.repository.core.RepositoryInformation; |
40 | 32 | import org.springframework.data.repository.core.support.RepositoryComposition; |
41 | 33 | import org.springframework.data.repository.core.support.RepositoryFragment; |
42 | 34 | import org.springframework.data.repository.query.QueryMethod; |
43 | 35 | import org.springframework.data.util.Lazy; |
44 | | -import org.springframework.data.util.TypeInformation; |
45 | 36 | import org.springframework.javapoet.ClassName; |
46 | 37 | import org.springframework.javapoet.FieldSpec; |
47 | 38 | import org.springframework.javapoet.MethodSpec; |
@@ -340,210 +331,6 @@ private void contributeMethod(Method method, @Nullable MethodContributorFactory |
340 | 331 | generationMetadata.addRepositoryMethod(method, contributor); |
341 | 332 | } |
342 | 333 |
|
343 | | - /** |
344 | | - * Value object to determine whether generics in a given {@link Method} can be resolved. Resolvable generics are e.g. |
345 | | - * declared on the method level (unbounded type variables, type variables using class boundaries). Considers |
346 | | - * collections and map types. |
347 | | - * <p> |
348 | | - * Considers resolvable: |
349 | | - * <ul> |
350 | | - * <li>Unbounded method-level type parameters {@code <T> T foo(Class<T>)}</li> |
351 | | - * <li>Bounded method-level type parameters that resolve to a class |
352 | | - * {@code <T extends Serializable> T foo(Class<T>)}</li> |
353 | | - * <li>Simple references to interface variables {@code T foo(), List<T> foo(…)}</li> |
354 | | - * <li>Unbounded wildcards {@code User foo(GeoJson<?>)}</li> |
355 | | - * </ul> |
356 | | - * Considers non-resolvable: |
357 | | - * <ul> |
358 | | - * <li>Parametrized bounds referring to known variables on method-level type parameters |
359 | | - * {@code <P extends T> T foo(Class<T>), List<? super T> foo()}</li> |
360 | | - * <li>Generally unresolvable generics</li> |
361 | | - * </ul> |
362 | | - * </p> |
363 | | - * |
364 | | - * @author Mark Paluch |
365 | | - */ |
366 | | - record ResolvableGenerics(Method method, Class<?> implClass, Set<Type> resolvableTypeVariables, |
367 | | - Set<Type> unwantedMethodVariables) { |
368 | | - |
369 | | - /** |
370 | | - * Create a new {@code ResolvableGenerics} object for the given {@link Method}. |
371 | | - * |
372 | | - * @param method |
373 | | - * @return |
374 | | - */ |
375 | | - public static ResolvableGenerics of(Method method, Class<?> implClass) { |
376 | | - return new ResolvableGenerics(method, implClass, getResolvableTypeVariables(method), |
377 | | - getUnwantedMethodVariables(method)); |
378 | | - } |
379 | | - |
380 | | - private static Set<Type> getResolvableTypeVariables(Method method) { |
381 | | - |
382 | | - Set<Type> simpleTypeVariables = new HashSet<>(); |
383 | | - |
384 | | - for (TypeVariable<Method> typeParameter : method.getTypeParameters()) { |
385 | | - if (isClassBounded(typeParameter.getBounds())) { |
386 | | - simpleTypeVariables.add(typeParameter); |
387 | | - } |
388 | | - } |
389 | | - |
390 | | - return simpleTypeVariables; |
391 | | - } |
392 | | - |
393 | | - private static Set<Type> getUnwantedMethodVariables(Method method) { |
394 | | - |
395 | | - Set<Type> unwanted = new HashSet<>(); |
396 | | - |
397 | | - for (TypeVariable<Method> typeParameter : method.getTypeParameters()) { |
398 | | - if (!isClassBounded(typeParameter.getBounds())) { |
399 | | - unwanted.add(typeParameter); |
400 | | - } |
401 | | - } |
402 | | - return unwanted; |
403 | | - } |
404 | | - |
405 | | - /** |
406 | | - * Check whether the {@link Method} has unresolvable generics when being considered in the context of the |
407 | | - * implementation class. |
408 | | - * |
409 | | - * @return |
410 | | - */ |
411 | | - public boolean hasUnresolvableGenerics() { |
412 | | - |
413 | | - ResolvableType resolvableType = ResolvableType.forMethodReturnType(method, implClass); |
414 | | - |
415 | | - if (isUnresolvable(resolvableType)) { |
416 | | - return true; |
417 | | - } |
418 | | - |
419 | | - for (int i = 0; i < method.getParameterCount(); i++) { |
420 | | - if (isUnresolvable(ResolvableType.forMethodParameter(method, i, implClass))) { |
421 | | - return true; |
422 | | - } |
423 | | - } |
424 | | - |
425 | | - return false; |
426 | | - } |
427 | | - |
428 | | - private boolean isUnresolvable(TypeInformation<?> typeInformation) { |
429 | | - return isUnresolvable(typeInformation.toResolvableType()); |
430 | | - } |
431 | | - |
432 | | - private boolean isUnresolvable(ResolvableType resolvableType) { |
433 | | - |
434 | | - if (isResolvable(resolvableType)) { |
435 | | - return false; |
436 | | - } |
437 | | - |
438 | | - if (isUnwanted(resolvableType)) { |
439 | | - return true; |
440 | | - } |
441 | | - |
442 | | - if (resolvableType.isAssignableFrom(Class.class)) { |
443 | | - return isUnresolvable(resolvableType.getGeneric(0)); |
444 | | - } |
445 | | - |
446 | | - TypeInformation<?> typeInformation = TypeInformation.of(resolvableType); |
447 | | - if (typeInformation.isMap() || typeInformation.isCollectionLike()) { |
448 | | - |
449 | | - for (ResolvableType type : resolvableType.getGenerics()) { |
450 | | - if (isUnresolvable(type)) { |
451 | | - return true; |
452 | | - } |
453 | | - } |
454 | | - |
455 | | - return false; |
456 | | - } |
457 | | - |
458 | | - if (typeInformation.getActualType() != null && typeInformation.getActualType() != typeInformation) { |
459 | | - return isUnresolvable(typeInformation.getRequiredActualType()); |
460 | | - } |
461 | | - |
462 | | - return resolvableType.hasUnresolvableGenerics(); |
463 | | - } |
464 | | - |
465 | | - private boolean isResolvable(Type[] types) { |
466 | | - |
467 | | - for (Type type : types) { |
468 | | - |
469 | | - if (resolvableTypeVariables.contains(type)) { |
470 | | - continue; |
471 | | - } |
472 | | - |
473 | | - if (isClass(type)) { |
474 | | - continue; |
475 | | - } |
476 | | - |
477 | | - return false; |
478 | | - } |
479 | | - |
480 | | - return true; |
481 | | - } |
482 | | - |
483 | | - private boolean isResolvable(ResolvableType resolvableType) { |
484 | | - |
485 | | - return testGenericType(resolvableType, it -> { |
486 | | - |
487 | | - if (resolvableTypeVariables.contains(it)) { |
488 | | - return true; |
489 | | - } |
490 | | - |
491 | | - if (it instanceof WildcardType wt) { |
492 | | - return isClassBounded(wt.getLowerBounds()) && isClassBounded(wt.getUpperBounds()); |
493 | | - } |
494 | | - |
495 | | - return false; |
496 | | - }); |
497 | | - } |
498 | | - |
499 | | - private boolean isUnwanted(ResolvableType resolvableType) { |
500 | | - |
501 | | - return testGenericType(resolvableType, o -> { |
502 | | - |
503 | | - if (o instanceof WildcardType wt) { |
504 | | - return !isResolvable(wt.getLowerBounds()) || !isResolvable(wt.getUpperBounds()); |
505 | | - } |
506 | | - |
507 | | - return unwantedMethodVariables.contains(o); |
508 | | - }); |
509 | | - } |
510 | | - |
511 | | - private static boolean testGenericType(ResolvableType resolvableType, Predicate<Type> predicate) { |
512 | | - |
513 | | - if (predicate.test(resolvableType.getType())) { |
514 | | - return true; |
515 | | - } |
516 | | - |
517 | | - ResolvableType[] generics = resolvableType.getGenerics(); |
518 | | - for (ResolvableType generic : generics) { |
519 | | - if (testGenericType(generic, predicate)) { |
520 | | - return true; |
521 | | - } |
522 | | - } |
523 | | - |
524 | | - return false; |
525 | | - } |
526 | | - |
527 | | - private static boolean isClassBounded(Type[] bounds) { |
528 | | - |
529 | | - for (Type bound : bounds) { |
530 | | - |
531 | | - if (isClass(bound)) { |
532 | | - continue; |
533 | | - } |
534 | | - |
535 | | - return false; |
536 | | - } |
537 | | - |
538 | | - return true; |
539 | | - } |
540 | | - |
541 | | - private static boolean isClass(Type type) { |
542 | | - return type instanceof Class; |
543 | | - } |
544 | | - |
545 | | - } |
546 | | - |
547 | 334 | /** |
548 | 335 | * Factory interface to conditionally create {@link MethodContributor} instances. An implementation may decide whether |
549 | 336 | * to return a {@link MethodContributor} or {@literal null}, if no method (code or metadata) should be contributed. |
|
0 commit comments