Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 9d7d551

Browse files
committed
Prevent StackOverflow when analyzing generic type
Closes gh-1323
1 parent deffea4 commit 9d7d551

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

spring-aot/src/main/java/org/springframework/aot/context/bootstrap/generator/infrastructure/ProtectedAccessAnalyzer.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.lang.reflect.Modifier;
2424
import java.lang.reflect.Parameter;
2525
import java.util.ArrayList;
26+
import java.util.HashSet;
2627
import java.util.List;
28+
import java.util.Set;
2729
import java.util.function.Function;
2830

2931
import org.springframework.aot.context.bootstrap.generator.bean.descriptor.BeanInstanceDescriptor;
@@ -68,7 +70,7 @@ public ProtectedAccessAnalysis analyze(BeanInstanceDescriptor descriptor) {
6870

6971
private List<ProtectedElement> analyze(ResolvableType target) {
7072
List<ProtectedElement> elements = new ArrayList<>();
71-
analyze(target, target, elements);
73+
analyze(new HashSet<>(), target, target, elements);
7274
return elements;
7375
}
7476

@@ -103,7 +105,12 @@ private List<ProtectedElement> analyze(Parameter[] parameters, Function<Integer,
103105
return protectedElements;
104106
}
105107

106-
private void analyze(ResolvableType rootType, ResolvableType target, List<ProtectedElement> elements) {
108+
private void analyze(Set<ResolvableType> seen, ResolvableType rootType, ResolvableType target,
109+
List<ProtectedElement> elements) {
110+
if (seen.contains(target)) {
111+
return;
112+
}
113+
seen.add(target);
107114
// resolve to the actual class as the proxy won't have the same characteristics
108115
ResolvableType nonProxyTarget = target.as(ClassUtils.getUserClass(target.toClass()));
109116
if (!isAccessible(nonProxyTarget.toClass())) {
@@ -117,7 +124,7 @@ private void analyze(ResolvableType rootType, ResolvableType target, List<Protec
117124
}
118125
if (nonProxyTarget.hasGenerics()) {
119126
for (ResolvableType generic : nonProxyTarget.getGenerics()) {
120-
analyze(rootType, generic, elements);
127+
analyze(seen, rootType, generic, elements);
121128
}
122129
}
123130
}

spring-aot/src/test/java/org/springframework/aot/context/bootstrap/generator/infrastructure/ProtectedAccessAnalyzerTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.aot.context.bootstrap.generator.sample.SimpleConfiguration;
2828
import org.springframework.aot.context.bootstrap.generator.sample.visibility.ProtectedParameter;
2929
import org.springframework.aot.context.bootstrap.generator.sample.visibility.PublicFactoryBean;
30+
import org.springframework.core.ResolvableType;
3031
import org.springframework.util.ReflectionUtils;
3132

3233
import static org.assertj.core.api.Assertions.assertThat;
@@ -152,6 +153,12 @@ void analyzeWithPackagePrivateGenericArgumentInTargetPackage() {
152153
PublicFactoryBean.class.getPackageName()).isAccessible()).isTrue();
153154
}
154155

156+
@Test
157+
void analyzeWithRecursiveType() {
158+
analyze(BeanInstanceDescriptor.of(ResolvableType.forClassWithGenerics(
159+
SelfReference.class, SelfReference.class)).build());
160+
}
161+
155162
private ProtectedAccessAnalysis analyze(BeanInstanceDescriptor descriptor) {
156163
return analyze(descriptor, "com.example.public");
157164
}
@@ -208,4 +215,13 @@ public String stringBean() {
208215

209216
}
210217

218+
static class SelfReference<T extends SelfReference<T>> {
219+
220+
@SuppressWarnings("unchecked")
221+
T getThis() {
222+
return (T) this;
223+
}
224+
225+
}
226+
211227
}

0 commit comments

Comments
 (0)