Avoid stack overflow in case of circular type reference
Issue: SPR-11522
This commit is contained in:
parent
93c8b7ab04
commit
3dfa7e9ac0
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -1700,6 +1700,22 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertSame(bean2, bean1.gi2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircularTypeReference() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("bean1", new RootBeanDefinition(StockServiceImpl.class));
|
||||
bf.registerBeanDefinition("bean2", new RootBeanDefinition(StockMovementDaoImpl.class));
|
||||
bf.registerBeanDefinition("bean3", new RootBeanDefinition(StockMovementImpl.class));
|
||||
bf.registerBeanDefinition("bean4", new RootBeanDefinition(StockMovementInstructionImpl.class));
|
||||
|
||||
StockServiceImpl service = bf.getBean(StockServiceImpl.class);
|
||||
assertSame(bf.getBean(StockMovementDaoImpl.class), service.stockMovementDao);
|
||||
}
|
||||
|
||||
|
||||
public static class ResourceInjectionBean {
|
||||
|
||||
|
|
@ -2650,4 +2666,35 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public interface StockMovement<P extends StockMovementInstruction> {
|
||||
}
|
||||
|
||||
|
||||
public interface StockMovementInstruction<C extends StockMovement> {
|
||||
}
|
||||
|
||||
|
||||
public interface StockMovementDao<S extends StockMovement> {
|
||||
}
|
||||
|
||||
|
||||
public static class StockMovementImpl<P extends StockMovementInstruction> implements StockMovement<P> {
|
||||
}
|
||||
|
||||
|
||||
public static class StockMovementInstructionImpl<C extends StockMovement> implements StockMovementInstruction<C> {
|
||||
}
|
||||
|
||||
|
||||
public static class StockMovementDaoImpl<E extends StockMovement> implements StockMovementDao<E> {
|
||||
}
|
||||
|
||||
|
||||
public static class StockServiceImpl {
|
||||
|
||||
@Autowired
|
||||
private StockMovementDao<StockMovement> stockMovementDao;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.lang.reflect.Type;
|
|||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.SerializableTypeWrapper.FieldTypeProvider;
|
||||
|
|
@ -188,10 +189,10 @@ public final class ResolvableType implements Serializable {
|
|||
* @return {@code true} if the specified {@code type} can be assigned to this {@code type}
|
||||
*/
|
||||
public boolean isAssignableFrom(ResolvableType type) {
|
||||
return isAssignableFrom(type, false);
|
||||
return isAssignableFrom(type, null);
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(ResolvableType type, boolean checkingGeneric) {
|
||||
private boolean isAssignableFrom(ResolvableType type, Map<ResolvableType, ResolvableType> matchedBefore) {
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
// If we cannot resolve types, we are not assignable
|
||||
|
|
@ -204,6 +205,10 @@ public final class ResolvableType implements Serializable {
|
|||
return (type.isArray() && getComponentType().isAssignableFrom(type.getComponentType()));
|
||||
}
|
||||
|
||||
if (matchedBefore != null && matchedBefore.get(this) == type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deal with wildcard bounds
|
||||
WildcardBounds ourBounds = WildcardBounds.get(this);
|
||||
WildcardBounds typeBounds = WildcardBounds.get(type);
|
||||
|
|
@ -220,7 +225,7 @@ public final class ResolvableType implements Serializable {
|
|||
}
|
||||
|
||||
// Main assignability check about to follow
|
||||
boolean exactMatch = checkingGeneric;
|
||||
boolean exactMatch = (matchedBefore != null); // We're checking nested generic variables now...
|
||||
boolean checkGenerics = true;
|
||||
Class<?> ourResolved = null;
|
||||
if (this.type instanceof TypeVariable) {
|
||||
|
|
@ -265,8 +270,12 @@ public final class ResolvableType implements Serializable {
|
|||
if (ourGenerics.length != typeGenerics.length) {
|
||||
return false;
|
||||
}
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<ResolvableType, ResolvableType>(1);
|
||||
}
|
||||
matchedBefore.put(this, type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true)) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue