Skip to content

Commit f1af8c5

Browse files
committed
Merge branch '2.1.x'
Closes gh-18889
2 parents d8545bd + 59bc3c5 commit f1af8c5

File tree

3 files changed

+62
-16
lines changed

3 files changed

+62
-16
lines changed

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import java.util.Map;
2727
import java.util.Set;
28+
import java.util.Stack;
2829

2930
import javax.annotation.processing.AbstractProcessor;
3031
import javax.annotation.processing.ProcessingEnvironment;
@@ -180,10 +181,10 @@ private void processElement(Element element) {
180181
if (annotation != null) {
181182
String prefix = getPrefix(annotation);
182183
if (element instanceof TypeElement) {
183-
processAnnotatedTypeElement(prefix, (TypeElement) element);
184+
processAnnotatedTypeElement(prefix, (TypeElement) element, new Stack<TypeElement>());
184185
}
185186
else if (element instanceof ExecutableElement) {
186-
processExecutableElement(prefix, (ExecutableElement) element);
187+
processExecutableElement(prefix, (ExecutableElement) element, new Stack<TypeElement>());
187188
}
188189
}
189190
}
@@ -192,13 +193,13 @@ else if (element instanceof ExecutableElement) {
192193
}
193194
}
194195

195-
private void processAnnotatedTypeElement(String prefix, TypeElement element) {
196+
private void processAnnotatedTypeElement(String prefix, TypeElement element, Stack<TypeElement> seen) {
196197
String type = this.metadataEnv.getTypeUtils().getQualifiedName(element);
197198
this.metadataCollector.add(ItemMetadata.newGroup(prefix, type, type, null));
198-
processTypeElement(prefix, element, null);
199+
processTypeElement(prefix, element, null, seen);
199200
}
200201

201-
private void processExecutableElement(String prefix, ExecutableElement element) {
202+
private void processExecutableElement(String prefix, ExecutableElement element, Stack<TypeElement> seen) {
202203
if ((!element.getModifiers().contains(Modifier.PRIVATE))
203204
&& (TypeKind.VOID != element.getReturnType().getKind())) {
204205
Element returns = this.processingEnv.getTypeUtils().asElement(element.getReturnType());
@@ -213,22 +214,27 @@ private void processExecutableElement(String prefix, ExecutableElement element)
213214
}
214215
else {
215216
this.metadataCollector.add(group);
216-
processTypeElement(prefix, (TypeElement) returns, element);
217+
processTypeElement(prefix, (TypeElement) returns, element, seen);
217218
}
218219
}
219220
}
220221
}
221222

222-
private void processTypeElement(String prefix, TypeElement element, ExecutableElement source) {
223-
new PropertyDescriptorResolver(this.metadataEnv).resolve(element, source).forEach((descriptor) -> {
224-
this.metadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));
225-
if (descriptor.isNested(this.metadataEnv)) {
226-
TypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()
227-
.asElement(descriptor.getType());
228-
String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());
229-
processTypeElement(nestedPrefix, nestedTypeElement, source);
230-
}
231-
});
223+
private void processTypeElement(String prefix, TypeElement element, ExecutableElement source,
224+
Stack<TypeElement> seen) {
225+
if (!seen.contains(element)) {
226+
seen.push(element);
227+
new PropertyDescriptorResolver(this.metadataEnv).resolve(element, source).forEach((descriptor) -> {
228+
this.metadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));
229+
if (descriptor.isNested(this.metadataEnv)) {
230+
TypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()
231+
.asElement(descriptor.getType());
232+
String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());
233+
processTypeElement(nestedPrefix, nestedTypeElement, source, seen);
234+
}
235+
});
236+
seen.pop();
237+
}
232238
}
233239

234240
private void processEndpoint(Element element, List<Element> annotations) {

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
2222
import org.springframework.boot.configurationprocessor.metadata.Metadata;
23+
import org.springframework.boot.configurationsample.recursive.RecursiveProperties;
2324
import org.springframework.boot.configurationsample.simple.ClassWithNestedProperties;
2425
import org.springframework.boot.configurationsample.simple.DeprecatedFieldSingleProperty;
2526
import org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty;
@@ -361,4 +362,9 @@ void constructorParameterPropertyWithInvalidDefaultValueOnCharacter() {
361362
.withMessageContaining("Compilation failed");
362363
}
363364

365+
@Test
366+
void recursivePropertiesDoNotCauseAStackOverflow() {
367+
compile(RecursiveProperties.class);
368+
}
369+
364370
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.configurationsample.recursive;
18+
19+
import org.springframework.boot.configurationsample.ConfigurationProperties;
20+
21+
@ConfigurationProperties("prefix")
22+
public class RecursiveProperties {
23+
24+
private RecursiveProperties recursive;
25+
26+
public RecursiveProperties getRecursive() {
27+
return this.recursive;
28+
}
29+
30+
public void setRecursive(RecursiveProperties recursive) {
31+
this.recursive = recursive;
32+
}
33+
34+
}

0 commit comments

Comments
 (0)