From 43d943f49abfed07bf3b06729dd46af77d6741e3 Mon Sep 17 00:00:00 2001 From: bnasslahsen Date: Sun, 5 Apr 2020 17:31:25 +0200 Subject: [PATCH] project review to keep compatibiliy with spring-boot-1 --- .../org/springdoc/core/ReturnTypeParser.java | 87 ++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/ReturnTypeParser.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/ReturnTypeParser.java index e83cbbe3b..39dbe7e27 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/ReturnTypeParser.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/ReturnTypeParser.java @@ -20,16 +20,99 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; -import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; +import org.springframework.lang.Nullable; public interface ReturnTypeParser { default Type getReturnType(MethodParameter methodParameter) { if (methodParameter.getGenericParameterType() instanceof ParameterizedType) - return GenericTypeResolver.resolveType(methodParameter.getGenericParameterType(),methodParameter.getContainingClass()); + return ReturnTypeParser.resolveType(methodParameter.getGenericParameterType(), methodParameter.getContainingClass()); return methodParameter.getParameterType(); } + + /** + * This is a copy of GenericTypeResolver.resolveType which is not available on spring 4. + * This also keeps compatibility with spring-boot 1 applications. + * Resolve the given generic type against the given context class, + * substituting type variables as far as possible. + * @param genericType the (potentially) generic type + * @param contextClass a context class for the target type, for example a class + * in which the target type appears in a method signature (can be {@code null}) + * @return the resolved type (possibly the given generic type as-is) + * @since 5.0 + */ + static Type resolveType(Type genericType, @Nullable Class contextClass) { + if (contextClass != null) { + if (genericType instanceof TypeVariable) { + ResolvableType resolvedTypeVariable = resolveVariable( + (TypeVariable) genericType, ResolvableType.forClass(contextClass)); + if (resolvedTypeVariable != ResolvableType.NONE) { + Class resolved = resolvedTypeVariable.resolve(); + if (resolved != null) { + return resolved; + } + } + } + else if (genericType instanceof ParameterizedType) { + ResolvableType resolvedType = ResolvableType.forType(genericType); + if (resolvedType.hasUnresolvableGenerics()) { + ParameterizedType parameterizedType = (ParameterizedType) genericType; + Class[] generics = new Class[parameterizedType.getActualTypeArguments().length]; + Type[] typeArguments = parameterizedType.getActualTypeArguments(); + ResolvableType contextType = ResolvableType.forClass(contextClass); + for (int i = 0; i < typeArguments.length; i++) { + Type typeArgument = typeArguments[i]; + if (typeArgument instanceof TypeVariable) { + ResolvableType resolvedTypeArgument = resolveVariable( + (TypeVariable) typeArgument, contextType); + if (resolvedTypeArgument != ResolvableType.NONE) { + generics[i] = resolvedTypeArgument.resolve(); + } + else { + generics[i] = ResolvableType.forType(typeArgument).resolve(); + } + } + else { + generics[i] = ResolvableType.forType(typeArgument).resolve(); + } + } + Class rawClass = resolvedType.getRawClass(); + if (rawClass != null) { + return ResolvableType.forClassWithGenerics(rawClass, generics).getType(); + } + } + } + } + return genericType; + } + + static ResolvableType resolveVariable(TypeVariable typeVariable, ResolvableType contextType) { + ResolvableType resolvedType; + if (contextType.hasGenerics()) { + resolvedType = ResolvableType.forType(typeVariable, contextType); + if (resolvedType.resolve() != null) { + return resolvedType; + } + } + + ResolvableType superType = contextType.getSuperType(); + if (superType != ResolvableType.NONE) { + resolvedType = resolveVariable(typeVariable, superType); + if (resolvedType.resolve() != null) { + return resolvedType; + } + } + for (ResolvableType ifc : contextType.getInterfaces()) { + resolvedType = resolveVariable(typeVariable, ifc); + if (resolvedType.resolve() != null) { + return resolvedType; + } + } + return ResolvableType.NONE; + } }