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
This commit is contained in:
Stephane Nicoll
2017-11-03 13:25:23 +01:00
parent ef39092b3b
commit fb76aa0150
4 changed files with 119 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ package org.springframework.context.index;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -29,7 +30,9 @@ import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
/**
@@ -42,6 +45,10 @@ import javax.lang.model.element.TypeElement;
*/
public class CandidateComponentsIndexer implements Processor {
private static final Set<ElementKind> TYPE_KINDS =
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
ElementKind.INTERFACE));
private MetadataStore metadataStore;
private MetadataCollector metadataCollector;
@@ -102,6 +109,11 @@ public class CandidateComponentsIndexer implements Processor {
}
private void processElement(Element element) {
addMetadataFor(element);
staticTypesIn(element.getEnclosedElements()).forEach(this::processElement);
}
private void addMetadataFor(Element element) {
Set<String> stereotypes = new LinkedHashSet<>();
this.stereotypesProviders.forEach(p -> stereotypes.addAll(p.getStereotypes(element)));
if (!stereotypes.isEmpty()) {
@@ -121,4 +133,14 @@ public class CandidateComponentsIndexer implements Processor {
}
}
private static List<TypeElement> staticTypesIn(Iterable<? extends Element> elements) {
List<TypeElement> list = new ArrayList<>();
for (Element e : elements) {
if (TYPE_KINDS.contains(e.getKind())
&& e.getModifiers().contains(Modifier.STATIC))
list.add(TypeElement.class.cast(e));
}
return list;
}
}

View File

@@ -38,6 +38,7 @@ import org.springframework.context.index.sample.SampleComponent;
import org.springframework.context.index.sample.SampleController;
import org.springframework.context.index.sample.SampleMetaController;
import org.springframework.context.index.sample.SampleMetaIndexedController;
import org.springframework.context.index.sample.SampleNonStaticEmbedded;
import org.springframework.context.index.sample.SampleNone;
import org.springframework.context.index.sample.SampleRepository;
import org.springframework.context.index.sample.SampleService;
@@ -45,6 +46,7 @@ import org.springframework.context.index.sample.cdi.SampleManagedBean;
import org.springframework.context.index.sample.cdi.SampleNamed;
import org.springframework.context.index.sample.jpa.SampleConverter;
import org.springframework.context.index.sample.jpa.SampleEmbeddable;
import org.springframework.context.index.sample.SampleEmbedded;
import org.springframework.context.index.sample.jpa.SampleEntity;
import org.springframework.context.index.sample.jpa.SampleMappedSuperClass;
import org.springframework.context.index.sample.type.Repo;
@@ -55,6 +57,7 @@ import org.springframework.context.index.sample.type.SmartRepo;
import org.springframework.context.index.sample.type.SpecializedRepo;
import org.springframework.context.index.test.TestCompiler;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@@ -198,6 +201,26 @@ public class CandidateComponentsIndexerTests {
testSingleComponent(Repo.class, Repo.class);
}
@Test
public void embeddedCandidatesAreDetected()
throws IOException, ClassNotFoundException {
// Validate nested type structure
String nestedType = "org.springframework.context.index.sample.SampleEmbedded.Another$AnotherPublicCandidate";
Class<?> type = ClassUtils.forName(nestedType, getClass().getClassLoader());
assertThat(type, sameInstance(SampleEmbedded.Another.AnotherPublicCandidate.class));
CandidateComponentsMetadata metadata = compile(SampleEmbedded.class);
assertThat(metadata, hasComponent(
SampleEmbedded.PublicCandidate.class, Component.class));
assertThat(metadata, hasComponent(nestedType, Component.class.getName()));
assertThat(metadata.getItems(), hasSize(2));
}
@Test
public void embeddedNonStaticCandidateAreIgnored() throws IOException {
CandidateComponentsMetadata metadata = compile(SampleNonStaticEmbedded.class);
assertThat(metadata.getItems(), hasSize(0));
}
private void testComponent(Class<?>... classes) throws IOException {
CandidateComponentsMetadata metadata = compile(classes);

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.index.sample;
import org.springframework.stereotype.Component;
/**
* Test candidate for an embedded {@link Component}.
*
* @author Stephane Nicoll
*/
public class SampleEmbedded {
@Component
public static class PublicCandidate {
}
public static class Another {
@Component
public static class AnotherPublicCandidate {
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.index.sample;
import org.springframework.stereotype.Component;
/**
* Candidate with a inner class that isn't static (and should therefore not be added).
*
* @author Stephane Nicoll
*/
public class SampleNonStaticEmbedded {
@Component
public class InvalidCandidate {
}
}