diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java index 17382ab6..554bae9a 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java @@ -16,9 +16,11 @@ package org.springframework.cloud.gateway.server.mvc.config; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -35,6 +37,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.ResolvableType; import org.springframework.core.type.filter.AssignableTypeFilter; /** @@ -85,6 +88,34 @@ public class GatewayMvcRuntimeHintsProcessor implements BeanFactoryInitializatio } private static Set> getTypesToRegister(String packageName) { + Set> classesToAdd = getClassesToAdd(packageName); + Set> genericsToAdd = new HashSet<>(); + Set> superTypes = new HashSet<>(); + Set> enclosingClasses = new HashSet<>(); + for (Class clazz : classesToAdd) { + ResolvableType resolvableType = ResolvableType.forType(clazz); + addGenericsForClass(genericsToAdd, resolvableType); + addSuperTypesForClass(resolvableType, superTypes, genericsToAdd); + addEnclosingClassesForClass(enclosingClasses, resolvableType.getRawClass()); + } + classesToAdd.addAll(genericsToAdd); + classesToAdd.addAll(superTypes); + classesToAdd.addAll(enclosingClasses); + return classesToAdd.stream().filter(Objects::nonNull).collect(Collectors.toSet()); + } + + private static void addEnclosingClassesForClass(Set> enclosingClasses, Class clazz) { + if (clazz == null) { + return; + } + Class enclosing = clazz.getEnclosingClass(); + if (enclosing != null) { + enclosingClasses.add(enclosing); + addEnclosingClassesForClass(enclosingClasses, enclosing); + } + } + + private static Set> getClassesToAdd(String packageName) { Set> classesToAdd = new HashSet<>(); ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); provider.addIncludeFilter(new AssignableTypeFilter(Object.class)); @@ -106,6 +137,24 @@ public class GatewayMvcRuntimeHintsProcessor implements BeanFactoryInitializatio return classesToAdd; } + private static void addGenericsForClass(Set> genericsToAdd, ResolvableType resolvableType) { + if (resolvableType.getSuperType().hasGenerics()) { + genericsToAdd.addAll(Arrays.stream(resolvableType.getSuperType().getGenerics()) + .map(ResolvableType::toClass) + .collect(Collectors.toSet())); + } + } + + private static void addSuperTypesForClass(ResolvableType resolvableType, Set> supertypesToAdd, + Set> genericsToAdd) { + ResolvableType superType = resolvableType.getSuperType(); + if (!ResolvableType.NONE.equals(superType)) { + addGenericsForClass(genericsToAdd, superType); + supertypesToAdd.add(superType.toClass()); + addSuperTypesForClass(superType, supertypesToAdd, genericsToAdd); + } + } + private static boolean shouldRegisterClass(Class clazz) { Set conditionClasses = beansConditionalOnClasses.getOrDefault(clazz.getName(), Collections.emptySet()); for (String conditionClass : conditionClasses) {