Skip to content

Commit fb76aa0

Browse files
committed
Detected candidate inner classes
This commit improves the indexer to also consider static inner classes on top of regular top level classes. Issue: SPR-16112
1 parent ef39092 commit fb76aa0

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

spring-context-indexer/src/main/java/org/springframework/context/index/CandidateComponentsIndexer.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.util.ArrayList;
2121
import java.util.Collections;
22+
import java.util.EnumSet;
2223
import java.util.LinkedHashSet;
2324
import java.util.List;
2425
import java.util.Set;
@@ -29,7 +30,9 @@
2930
import javax.lang.model.SourceVersion;
3031
import javax.lang.model.element.AnnotationMirror;
3132
import javax.lang.model.element.Element;
33+
import javax.lang.model.element.ElementKind;
3234
import javax.lang.model.element.ExecutableElement;
35+
import javax.lang.model.element.Modifier;
3336
import javax.lang.model.element.TypeElement;
3437

3538
/**
@@ -42,6 +45,10 @@
4245
*/
4346
public class CandidateComponentsIndexer implements Processor {
4447

48+
private static final Set<ElementKind> TYPE_KINDS =
49+
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
50+
ElementKind.INTERFACE));
51+
4552
private MetadataStore metadataStore;
4653

4754
private MetadataCollector metadataCollector;
@@ -102,6 +109,11 @@ private List<StereotypesProvider> getStereotypesProviders(ProcessingEnvironment
102109
}
103110

104111
private void processElement(Element element) {
112+
addMetadataFor(element);
113+
staticTypesIn(element.getEnclosedElements()).forEach(this::processElement);
114+
}
115+
116+
private void addMetadataFor(Element element) {
105117
Set<String> stereotypes = new LinkedHashSet<>();
106118
this.stereotypesProviders.forEach(p -> stereotypes.addAll(p.getStereotypes(element)));
107119
if (!stereotypes.isEmpty()) {
@@ -121,4 +133,14 @@ private void writeMetaData() {
121133
}
122134
}
123135

136+
private static List<TypeElement> staticTypesIn(Iterable<? extends Element> elements) {
137+
List<TypeElement> list = new ArrayList<>();
138+
for (Element e : elements) {
139+
if (TYPE_KINDS.contains(e.getKind())
140+
&& e.getModifiers().contains(Modifier.STATIC))
141+
list.add(TypeElement.class.cast(e));
142+
}
143+
return list;
144+
}
145+
124146
}

spring-context-indexer/src/test/java/org/springframework/context/index/CandidateComponentsIndexerTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@
3838
import org.springframework.context.index.sample.SampleController;
3939
import org.springframework.context.index.sample.SampleMetaController;
4040
import org.springframework.context.index.sample.SampleMetaIndexedController;
41+
import org.springframework.context.index.sample.SampleNonStaticEmbedded;
4142
import org.springframework.context.index.sample.SampleNone;
4243
import org.springframework.context.index.sample.SampleRepository;
4344
import org.springframework.context.index.sample.SampleService;
4445
import org.springframework.context.index.sample.cdi.SampleManagedBean;
4546
import org.springframework.context.index.sample.cdi.SampleNamed;
4647
import org.springframework.context.index.sample.jpa.SampleConverter;
4748
import org.springframework.context.index.sample.jpa.SampleEmbeddable;
49+
import org.springframework.context.index.sample.SampleEmbedded;
4850
import org.springframework.context.index.sample.jpa.SampleEntity;
4951
import org.springframework.context.index.sample.jpa.SampleMappedSuperClass;
5052
import org.springframework.context.index.sample.type.Repo;
@@ -55,6 +57,7 @@
5557
import org.springframework.context.index.sample.type.SpecializedRepo;
5658
import org.springframework.context.index.test.TestCompiler;
5759
import org.springframework.stereotype.Component;
60+
import org.springframework.util.ClassUtils;
5861

5962
import static org.hamcrest.Matchers.*;
6063
import static org.junit.Assert.*;
@@ -198,6 +201,26 @@ public void typeStereotypeOnIndexedInterface() throws IOException {
198201
testSingleComponent(Repo.class, Repo.class);
199202
}
200203

204+
@Test
205+
public void embeddedCandidatesAreDetected()
206+
throws IOException, ClassNotFoundException {
207+
// Validate nested type structure
208+
String nestedType = "org.springframework.context.index.sample.SampleEmbedded.Another$AnotherPublicCandidate";
209+
Class<?> type = ClassUtils.forName(nestedType, getClass().getClassLoader());
210+
assertThat(type, sameInstance(SampleEmbedded.Another.AnotherPublicCandidate.class));
211+
212+
CandidateComponentsMetadata metadata = compile(SampleEmbedded.class);
213+
assertThat(metadata, hasComponent(
214+
SampleEmbedded.PublicCandidate.class, Component.class));
215+
assertThat(metadata, hasComponent(nestedType, Component.class.getName()));
216+
assertThat(metadata.getItems(), hasSize(2));
217+
}
218+
219+
@Test
220+
public void embeddedNonStaticCandidateAreIgnored() throws IOException {
221+
CandidateComponentsMetadata metadata = compile(SampleNonStaticEmbedded.class);
222+
assertThat(metadata.getItems(), hasSize(0));
223+
}
201224

202225
private void testComponent(Class<?>... classes) throws IOException {
203226
CandidateComponentsMetadata metadata = compile(classes);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2017 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+
* http://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.context.index.sample;
18+
19+
import org.springframework.stereotype.Component;
20+
21+
/**
22+
* Test candidate for an embedded {@link Component}.
23+
*
24+
* @author Stephane Nicoll
25+
*/
26+
public class SampleEmbedded {
27+
28+
@Component
29+
public static class PublicCandidate {
30+
31+
}
32+
33+
public static class Another {
34+
35+
@Component
36+
public static class AnotherPublicCandidate {
37+
38+
}
39+
}
40+
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2002-2017 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+
* http://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.context.index.sample;
18+
19+
import org.springframework.stereotype.Component;
20+
21+
/**
22+
* Candidate with a inner class that isn't static (and should therefore not be added).
23+
*
24+
* @author Stephane Nicoll
25+
*/
26+
public class SampleNonStaticEmbedded {
27+
28+
@Component
29+
public class InvalidCandidate {
30+
31+
}
32+
33+
}

0 commit comments

Comments
 (0)