Permalink
Browse files

Avoid stack overflow in case of circular type reference

Issue: SPR-11522
  • Loading branch information...
1 parent 93c8b7a commit 3dfa7e9ac0ec070b52f580e11a279a7b7f64804f @jhoeller jhoeller committed Mar 6, 2014
@@ -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 void testGenericsBasedInjectionIntoTypeVariableSelectingBestMatch() {
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 String doSomethingMoreGeneric(Object o) {
}
}
+
+ 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.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 Object getSource() {
* @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 @@ private boolean isAssignableFrom(ResolvableType type, boolean checkingGeneric) {
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 @@ private boolean isAssignableFrom(ResolvableType type, boolean checkingGeneric) {
}
// 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 @@ private boolean isAssignableFrom(ResolvableType type, boolean checkingGeneric) {
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;
}
}

0 comments on commit 3dfa7e9

Please sign in to comment.