Browse Source

ResolvableType-based matching respects generic factory method return type

Includes consistent use of ResolvableType.resolve() wherever applicable.

Issue: SPR-15011
pull/1255/head
Juergen Hoeller 9 years ago
parent
commit
4c005e6336
  1. 2
      spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java
  2. 32
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  3. 16
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
  4. 12
      spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java
  5. 27
      spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
  6. 2
      spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
  7. 8
      spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
  8. 8
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
  9. 8
      spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java
  10. 8
      spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java
  11. 29
      spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
  12. 2
      spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java
  13. 2
      spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java
  14. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java

2
spring-beans/src/main/java/org/springframework/beans/factory/NoSuchBeanDefinitionException.java

@ -109,7 +109,7 @@ public class NoSuchBeanDefinitionException extends BeansException {
* that failed. * that failed.
*/ */
public Class<?> getBeanType() { public Class<?> getBeanType() {
return (this.resolvableType != null ? this.resolvableType.getRawClass() : null); return (this.resolvableType != null ? this.resolvableType.resolve() : null);
} }
/** /**

32
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -74,6 +74,7 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered; import org.springframework.core.PriorityOrdered;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -672,9 +673,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #createBean * @see #createBean
*/ */
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> preResolved = mbd.resolvedFactoryMethodReturnType; ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
if (preResolved != null) { if (cachedReturnType != null) {
return preResolved; return cachedReturnType.resolve();
} }
Class<?> factoryClass; Class<?> factoryClass;
@ -698,11 +699,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (factoryClass == null) { if (factoryClass == null) {
return null; return null;
} }
factoryClass = ClassUtils.getUserClass(factoryClass);
// If all factory methods have the same return type, return that type. // If all factory methods have the same return type, return that type.
// Can't clearly figure out exact method due to type converting / autowiring! // Can't clearly figure out exact method due to type converting / autowiring!
Class<?> commonType = null; Class<?> commonType = null;
boolean cache = false; Method uniqueCandidate = null;
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount(); int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass); Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
for (Method factoryMethod : candidates) { for (Method factoryMethod : candidates) {
@ -736,8 +738,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader()); factoryMethod, args, getBeanClassLoader());
if (returnType != null) { if (returnType != null) {
cache = true; uniqueCandidate = (commonType == null ? factoryMethod : null);
commonType = ClassUtils.determineCommonAncestor(returnType, commonType); commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
if (commonType == null) {
// Ambiguous return types found: return null to indicate "not determinable".
return null;
}
} }
} }
catch (Throwable ex) { catch (Throwable ex) {
@ -747,22 +753,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
} }
} }
else { else {
uniqueCandidate = (commonType == null ? factoryMethod : null);
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType); commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
if (commonType == null) {
// Ambiguous return types found: return null to indicate "not determinable".
return null;
}
} }
} }
} }
if (commonType != null) { if (commonType != null) {
// Clear return type found: all factory methods return same type. // Clear return type found: all factory methods return same type.
if (cache) { mbd.factoryMethodReturnType = (uniqueCandidate != null ?
mbd.resolvedFactoryMethodReturnType = commonType; ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
}
return commonType;
}
else {
// Ambiguous return types found: return null to indicate "not determinable".
return null;
} }
return commonType;
} }
/** /**

16
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

@ -513,7 +513,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Retrieve corresponding bean definition. // Retrieve corresponding bean definition.
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class<?> classToMatch = typeToMatch.getRawClass(); Class<?> classToMatch = typeToMatch.resolve();
if (classToMatch == null) {
classToMatch = FactoryBean.class;
}
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ? Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch}); new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
@ -553,6 +556,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
} }
} }
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
if (resolvableType != null && resolvableType.resolve() == beanType) {
return typeToMatch.isAssignableFrom(resolvableType);
}
return typeToMatch.isAssignableFrom(beanType); return typeToMatch.isAssignableFrom(beanType);
} }
} }
@ -1443,6 +1453,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @return the type of the bean, or {@code null} if not predictable * @return the type of the bean, or {@code null} if not predictable
*/ */
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> targetType = mbd.getTargetType();
if (targetType != null) {
return targetType;
}
if (mbd.getFactoryMethodName() != null) { if (mbd.getFactoryMethodName() != null) {
return null; return null;
} }

12
spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -162,8 +162,8 @@ abstract class AutowireUtils {
* Determine the target type for the generic return type of the given * Determine the target type for the generic return type of the given
* <em>generic factory method</em>, where formal type variables are declared * <em>generic factory method</em>, where formal type variables are declared
* on the given method itself. * on the given method itself.
* <p>For example, given a factory method with the following signature, * <p>For example, given a factory method with the following signature, if
* if {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected * {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
* method for {@code creatProxy()} and an {@code Object[]} array containing * method for {@code creatProxy()} and an {@code Object[]} array containing
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will * {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
* infer that the target return type is {@code MyService}. * infer that the target return type is {@code MyService}.
@ -184,9 +184,9 @@ abstract class AutowireUtils {
* @param method the method to introspect (never {@code null}) * @param method the method to introspect (never {@code null})
* @param args the arguments that will be supplied to the method when it is * @param args the arguments that will be supplied to the method when it is
* invoked (never {@code null}) * invoked (never {@code null})
* @param classLoader the ClassLoader to resolve class names against, if necessary * @param classLoader the ClassLoader to resolve class names against,
* (never {@code null}) * if necessary (never {@code null})
* @return the resolved target return type, the standard return type, or {@code null} * @return the resolved target return type or the standard method return type
* @since 3.2.5 * @since 3.2.5
*/ */
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) { public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {

27
spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java

@ -147,22 +147,23 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) { protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
// Should typically be set for any kind of factory method, since the BeanFactory // Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver... // pre-resolves them before reaching out to the AutowireCandidateResolver...
Class<?> preResolved = rbd.resolvedFactoryMethodReturnType; ResolvableType returnType = rbd.factoryMethodReturnType;
if (preResolved != null) { if (returnType == null) {
return ResolvableType.forClass(preResolved); Method factoryMethod = rbd.getResolvedFactoryMethod();
if (factoryMethod != null) {
returnType = ResolvableType.forMethodReturnType(factoryMethod);
}
} }
else { if (returnType != null) {
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod(); Class<?> resolvedClass = returnType.resolve();
if (resolvedFactoryMethod != null) { if (resolvedClass != null && descriptor.getDependencyType().isAssignableFrom(resolvedClass)) {
if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) { // Only use factory method metadata if the return type is actually expressive enough
// Only use factory method metadata if the return type is actually expressive enough // for our dependency. Otherwise, the returned instance type may have matched instead
// for our dependency. Otherwise, the returned instance type may have matched instead // in case of a singleton instance having been registered with the container already.
// in case of a singleton instance having been registered with the container already. return returnType;
return ResolvableType.forMethodReturnType(resolvedFactoryMethod);
}
} }
return null;
} }
return null;
} }

2
spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java

@ -65,7 +65,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
volatile Class<?> resolvedTargetType; volatile Class<?> resolvedTargetType;
/** Package-visible field for caching the return type of a generically typed factory method */ /** Package-visible field for caching the return type of a generically typed factory method */
volatile Class<?> resolvedFactoryMethodReturnType; volatile ResolvableType factoryMethodReturnType;
/** Common lock for the four constructor fields below */ /** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object(); final Object constructorArgumentLock = new Object();

8
spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java

@ -248,7 +248,13 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override @Override
public String[] getBeanNamesForType(ResolvableType type) { public String[] getBeanNamesForType(ResolvableType type) {
boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type.getRawClass())); boolean isFactoryType = false;
if (type != null) {
Class<?> resolved = type.resolve();
if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
isFactoryType = true;
}
}
List<String> matches = new ArrayList<>(); List<String> matches = new ArrayList<>();
for (Map.Entry<String, Object> entry : this.beans.entrySet()) { for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
String name = entry.getKey(); String name = entry.getKey();

8
spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

@ -1295,7 +1295,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
} }
catch (UnsatisfiedDependencyException ex) { catch (UnsatisfiedDependencyException ex) {
// expected // expected
ex.printStackTrace();
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class, assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
ex.getInjectionPoint().getField().getDeclaringClass()); ex.getInjectionPoint().getField().getDeclaringClass());
} }
@ -1681,9 +1680,6 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertSame(ir, bean.integerRepositoryMap.get("integerRepository")); assertSame(ir, bean.integerRepositoryMap.get("integerRepository"));
} }
@Qualifier("integerRepo")
private Repository<?> integerRepositoryQualifierProvider;
@Test @Test
public void testGenericsBasedFieldInjectionWithSimpleMatch() { public void testGenericsBasedFieldInjectionWithSimpleMatch() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@ -2194,6 +2190,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
} }
@Qualifier("integerRepo")
private Repository<?> integerRepositoryQualifierProvider;
public static class ResourceInjectionBean { public static class ResourceInjectionBean {
@Autowired(required = false) @Autowired(required = false)

8
spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java

@ -343,17 +343,15 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
ResolvableType payloadType = null; ResolvableType payloadType = null;
if (event instanceof PayloadApplicationEvent) { if (event instanceof PayloadApplicationEvent) {
PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event; PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;
payloadType = payloadEvent.getResolvableType().as( payloadType = payloadEvent.getResolvableType().as(PayloadApplicationEvent.class).getGeneric();
PayloadApplicationEvent.class).getGeneric(0);
} }
for (ResolvableType declaredEventType : this.declaredEventTypes) { for (ResolvableType declaredEventType : this.declaredEventTypes) {
if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) && payloadType != null) {
&& payloadType != null) {
if (declaredEventType.isAssignableFrom(payloadType)) { if (declaredEventType.isAssignableFrom(payloadType)) {
return declaredEventType; return declaredEventType;
} }
} }
if (declaredEventType.getRawClass().isAssignableFrom(event.getClass())) { if (declaredEventType.getRawClass().isInstance(event)) {
return declaredEventType; return declaredEventType;
} }
} }

8
spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -60,8 +60,8 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) { public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) { if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.getRawClass(); Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return ((SmartApplicationListener) this.delegate).supportsEventType(eventClass); return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
} }
else { else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType)); return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
@ -70,7 +70,7 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
@Override @Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return supportsEventType(ResolvableType.forType(eventType)); return supportsEventType(ResolvableType.forClass(eventType));
} }
@Override @Override

29
spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java

@ -43,6 +43,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.componentscan.simple.SimpleComponent; import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DescriptiveResource; import org.springframework.core.io.DescriptiveResource;
@ -50,6 +51,7 @@ import org.springframework.stereotype.Component;
import org.springframework.tests.sample.beans.ITestBean; import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean; import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -522,6 +524,33 @@ public class ConfigurationClassPostProcessorTests {
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer")); assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
} }
@Test
public void genericsBasedInjectionWithLateGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}
@Test
public void genericsBasedInjectionWithEarlyGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}
@Test @Test
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() { public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();

2
spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java

@ -283,7 +283,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
return this.returnValue.getClass(); return this.returnValue.getClass();
} }
if (!ResolvableType.NONE.equals(this.returnType)) { if (!ResolvableType.NONE.equals(this.returnType)) {
return this.returnType.getRawClass(); return this.returnType.resolve();
} }
return super.getParameterType(); return super.getParameterType();
} }

2
spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java

@ -436,7 +436,7 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
return; return;
} }
Type type = handler.getPayloadType(stompHeaders); Type type = handler.getPayloadType(stompHeaders);
Class<?> payloadType = ResolvableType.forType(type).getRawClass(); Class<?> payloadType = ResolvableType.forType(type).resolve();
Object object = getMessageConverter().fromMessage(message, payloadType); Object object = getMessageConverter().fromMessage(message, payloadType);
if (object == null) { if (object == null) {
throw new MessageConversionException("No suitable converter, payloadType=" + payloadType + throw new MessageConversionException("No suitable converter, payloadType=" + payloadType +

2
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java

@ -285,7 +285,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
return this.returnValue.getClass(); return this.returnValue.getClass();
} }
if (!ResolvableType.NONE.equals(this.returnType)) { if (!ResolvableType.NONE.equals(this.returnType)) {
return this.returnType.getRawClass(); return this.returnType.resolve();
} }
return super.getParameterType(); return super.getParameterType();
} }

Loading…
Cancel
Save