Revised indexer implementation

Issue: SPR-11890
This commit is contained in:
Juergen Hoeller 2017-01-17 12:46:55 +01:00
parent 0c99346829
commit 5471d6a465
20 changed files with 146 additions and 174 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -18,83 +18,98 @@ package org.springframework.context.index;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Completion;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import org.springframework.context.index.metadata.CandidateComponentsMetadata;
import org.springframework.context.index.metadata.ItemMetadata;
/**
* Annotation {@link Processor} that writes {@link CandidateComponentsMetadata}
* file for spring components.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 5.0
*/
@SupportedAnnotationTypes({"*"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class CandidateComponentsIndexer extends AbstractProcessor {
public class CandidateComponentsIndexer implements Processor {
private MetadataStore metadataStore;
private MetadataCollector metadataCollector;
private TypeUtils typeUtils;
private TypeHelper typeHelper;
private List<StereotypesProvider> stereotypesProviders;
@Override
public Set<String> getSupportedOptions() {
return Collections.emptySet();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton("*");
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public synchronized void init(ProcessingEnvironment env) {
this.stereotypesProviders = getStereotypesProviders(env);
this.typeUtils = new TypeUtils(env);
this.typeHelper = new TypeHelper(env);
this.metadataStore = new MetadataStore(env);
this.metadataCollector = new MetadataCollector(env,
this.metadataStore.readMetadata());
this.metadataCollector = new MetadataCollector(env, this.metadataStore.readMetadata());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
this.metadataCollector.processing(roundEnv);
roundEnv.getRootElements().forEach(this::processElement);
if (roundEnv.processingOver()) {
writeMetaData();
}
return false;
}
protected List<StereotypesProvider> getStereotypesProviders(ProcessingEnvironment env) {
@Override
public Iterable<? extends Completion> getCompletions(
Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
return Collections.emptyList();
}
private List<StereotypesProvider> getStereotypesProviders(ProcessingEnvironment env) {
List<StereotypesProvider> result = new ArrayList<>();
TypeUtils typeUtils = new TypeUtils(env);
result.add(new IndexedStereotypesProvider(typeUtils));
result.add(new StandardStereotypesProvider(typeUtils));
TypeHelper typeHelper = new TypeHelper(env);
result.add(new IndexedStereotypesProvider(typeHelper));
result.add(new StandardStereotypesProvider(typeHelper));
result.add(new PackageInfoStereotypesProvider());
return result;
}
private void processElement(Element element) {
Set<String> stereotypes = new LinkedHashSet<>();
this.stereotypesProviders.forEach(p -> {
stereotypes.addAll(p.getStereotypes(element));
});
this.stereotypesProviders.forEach(p -> stereotypes.addAll(p.getStereotypes(element)));
if (!stereotypes.isEmpty()) {
this.metadataCollector.add(new ItemMetadata(
this.typeUtils.getType(element), stereotypes));
this.metadataCollector.add(new ItemMetadata(this.typeHelper.getType(element), stereotypes));
}
}
protected CandidateComponentsMetadata writeMetaData() {
private CandidateComponentsMetadata writeMetaData() {
CandidateComponentsMetadata metadata = this.metadataCollector.getMetadata();
if (!metadata.getItems().isEmpty()) {
try {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.index.metadata;
package org.springframework.context.index;
import java.util.ArrayList;
import java.util.Collections;
@ -26,14 +26,16 @@ import java.util.List;
* @author Stephane Nicoll
* @since 5.0
*/
public class CandidateComponentsMetadata {
class CandidateComponentsMetadata {
private final List<ItemMetadata> items;
public CandidateComponentsMetadata() {
this.items = new ArrayList<>();
}
public void add(ItemMetadata item) {
this.items.add(item);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -29,17 +29,20 @@ import javax.lang.model.element.ElementKind;
* honors stereotypes defined this way on meta-annotations.
*
* @author Stephane Nicoll
* @since 5.0
*/
class IndexedStereotypesProvider implements StereotypesProvider {
private static final String INDEXED_ANNOTATION = "org.springframework.stereotype.Indexed";
private final TypeUtils typeUtils;
private final TypeHelper typeHelper;
public IndexedStereotypesProvider(TypeUtils typeUtils) {
this.typeUtils = typeUtils;
public IndexedStereotypesProvider(TypeHelper typeHelper) {
this.typeHelper = typeHelper;
}
@Override
public Set<String> getStereotypes(Element element) {
Set<String> stereotypes = new LinkedHashSet<>();
@ -56,7 +59,7 @@ class IndexedStereotypesProvider implements StereotypesProvider {
private void collectStereotypesOnAnnotations(Set<Element> seen, Set<String> stereotypes,
Element element) {
for (AnnotationMirror annotation : this.typeUtils.getAllAnnotationMirrors(element)) {
for (AnnotationMirror annotation : this.typeHelper.getAllAnnotationMirrors(element)) {
Element next = collectStereotypes(seen, stereotypes, element, annotation);
if (next != null) {
collectStereotypesOnAnnotations(seen, stereotypes, next);
@ -70,21 +73,22 @@ class IndexedStereotypesProvider implements StereotypesProvider {
if (!seen.contains(type)) {
seen.add(type);
if (isAnnotatedWithIndexed(type)) {
stereotypes.add(this.typeUtils.getType(type));
stereotypes.add(this.typeHelper.getType(type));
}
Element superClass = this.typeUtils.getSuperClass(type);
Element superClass = this.typeHelper.getSuperClass(type);
if (superClass != null) {
collectStereotypesOnTypes(seen, stereotypes, superClass);
}
this.typeUtils.getDirectInterfaces(type).forEach(
this.typeHelper.getDirectInterfaces(type).forEach(
i -> collectStereotypesOnTypes(seen, stereotypes, i));
}
}
private Element collectStereotypes(Set<Element> seen, Set<String> stereotypes,
Element element, AnnotationMirror annotation) {
if (isIndexedAnnotation(annotation)) {
stereotypes.add(this.typeUtils.getType(element));
stereotypes.add(this.typeHelper.getType(element));
}
return getCandidateAnnotationElement(seen, annotation);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.index.metadata;
package org.springframework.context.index;
import java.util.HashSet;
import java.util.Set;
@ -28,17 +28,19 @@ import java.util.Set;
* @author Stephane Nicoll
* @since 5.0
*/
public class ItemMetadata {
class ItemMetadata {
private final String type;
private final Set<String> stereotypes;
public ItemMetadata(String type, Set<String> stereotypes) {
this.type = type;
this.stereotypes = new HashSet<>(stereotypes);
}
public String getType() {
return this.type;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -25,13 +25,11 @@ import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import org.springframework.context.index.metadata.ItemMetadata;
import org.springframework.context.index.metadata.CandidateComponentsMetadata;
/**
* Used by {@link CandidateComponentsIndexer} to collect {@link CandidateComponentsMetadata}.
*
* @author Stephane Nicoll
* @since 5.0
*/
class MetadataCollector {
@ -41,22 +39,25 @@ class MetadataCollector {
private final CandidateComponentsMetadata previousMetadata;
private final TypeUtils typeUtils;
private final TypeHelper typeHelper;
private final Set<String> processedSourceTypes = new HashSet<String>();
/**
* Creates a new {@code MetadataProcessor} instance.
* Create a new {@code MetadataProcessor} instance.
* @param processingEnvironment The processing environment of the build
* @param previousMetadata Any previous metadata or {@code null}
*/
public MetadataCollector(ProcessingEnvironment processingEnvironment,
CandidateComponentsMetadata previousMetadata) {
this.processingEnvironment = processingEnvironment;
this.previousMetadata = previousMetadata;
this.typeUtils = new TypeUtils(processingEnvironment);
this.typeHelper = new TypeHelper(processingEnvironment);
}
public void processing(RoundEnvironment roundEnv) {
for (Element element : roundEnv.getRootElements()) {
markAsProcessed(element);
@ -65,7 +66,7 @@ class MetadataCollector {
private void markAsProcessed(Element element) {
if (element instanceof TypeElement) {
this.processedSourceTypes.add(this.typeUtils.getType(element));
this.processedSourceTypes.add(this.typeHelper.getType(element));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -23,13 +23,11 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import org.springframework.context.index.metadata.PropertiesMarshaller;
import org.springframework.context.index.metadata.CandidateComponentsMetadata;
/**
* Store {@link CandidateComponentsMetadata} on the filesystem.
*
* @author Stephane Nicoll
* @since 5.0
*/
class MetadataStore {
@ -37,15 +35,18 @@ class MetadataStore {
private final ProcessingEnvironment environment;
public MetadataStore(ProcessingEnvironment environment) {
this.environment = environment;
}
public CandidateComponentsMetadata readMetadata() {
try {
return readMetadata(getMetadataResource().openInputStream());
}
catch (IOException ex) {
// Failed to read metadata -> ignore.
return null;
}
}
@ -53,17 +54,15 @@ class MetadataStore {
public void writeMetadata(CandidateComponentsMetadata metadata) throws IOException {
if (!metadata.getItems().isEmpty()) {
try (OutputStream outputStream = createMetadataResource().openOutputStream()) {
new PropertiesMarshaller().write(metadata, outputStream);
PropertiesMarshaller.write(metadata, outputStream);
}
}
}
private CandidateComponentsMetadata readMetadata(InputStream in) throws IOException {
try {
return new PropertiesMarshaller().read(in);
}
catch (IOException ex) {
return null;
return PropertiesMarshaller.read(in);
}
finally {
in.close();
@ -71,13 +70,11 @@ class MetadataStore {
}
private FileObject getMetadataResource() throws IOException {
return this.environment.getFiler()
.getResource(StandardLocation.CLASS_OUTPUT, "", METADATA_PATH);
return this.environment.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", METADATA_PATH);
}
private FileObject createMetadataResource() throws IOException {
return this.environment.getFiler()
.createResource(StandardLocation.CLASS_OUTPUT, "", METADATA_PATH);
return this.environment.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", METADATA_PATH);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -26,11 +26,13 @@ import javax.lang.model.element.ElementKind;
* {@value STEREOTYPE} stereotype for each package-info.
*
* @author Stephane Nicoll
* @since 5.0
*/
class PackageInfoStereotypesProvider implements StereotypesProvider {
public static final String STEREOTYPE = "package-info";
@Override
public Set<String> getStereotypes(Element element) {
Set<String> stereotypes = new HashSet<>();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.index.metadata;
package org.springframework.context.index;
import java.io.IOException;
import java.io.InputStream;
@ -31,17 +31,15 @@ import java.util.Set;
* @author Stephane Nicoll
* @since 5.0
*/
public class PropertiesMarshaller {
public void write(CandidateComponentsMetadata metadata, OutputStream out)
throws IOException {
abstract class PropertiesMarshaller {
public static void write(CandidateComponentsMetadata metadata, OutputStream out) throws IOException {
Properties props = new Properties();
metadata.getItems().forEach(m -> props.put(m.getType(), String.join(",", m.getStereotypes())));
props.store(out, "");
}
public CandidateComponentsMetadata read(InputStream in) throws IOException {
public static CandidateComponentsMetadata read(InputStream in) throws IOException {
CandidateComponentsMetadata result = new CandidateComponentsMetadata();
Properties props = new Properties();
props.load(in);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -27,15 +27,18 @@ import javax.lang.model.element.ElementKind;
* {@code javax.*} annotation placed on a class or interface.
*
* @author Stephane Nicoll
* @since 5.0
*/
class StandardStereotypesProvider implements StereotypesProvider {
private final TypeUtils typeUtils;
private final TypeHelper typeHelper;
StandardStereotypesProvider(TypeUtils typeUtils) {
this.typeUtils = typeUtils;
StandardStereotypesProvider(TypeHelper typeHelper) {
this.typeHelper = typeHelper;
}
@Override
public Set<String> getStereotypes(Element element) {
Set<String> stereotypes = new LinkedHashSet<>();
@ -43,8 +46,8 @@ class StandardStereotypesProvider implements StereotypesProvider {
if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) {
return stereotypes;
}
for (AnnotationMirror annotation : this.typeUtils.getAllAnnotationMirrors(element)) {
String type = this.typeUtils.getType(annotation);
for (AnnotationMirror annotation : this.typeHelper.getAllAnnotationMirrors(element)) {
String type = this.typeHelper.getType(annotation);
if (type.startsWith("javax.")) {
stereotypes.add(type);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -20,11 +20,12 @@ import java.util.Set;
import javax.lang.model.element.Element;
/**
* Provide the list of stereotypes that match an {@link Element}. If an element
* has one more stereotypes, it is referenced in the index of candidate
* components and each stereotype can be queried individually.
* Provide the list of stereotypes that match an {@link Element}.
* If an element has one more stereotypes, it is referenced in the index
* of candidate components and each stereotype can be queried individually.
*
* @author Stephane Nicoll
* @since 5.0
*/
interface StereotypesProvider {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -31,18 +31,21 @@ import javax.lang.model.util.Types;
* Type utilities.
*
* @author Stephane Nicoll
* @since 5.0
*/
class TypeUtils {
class TypeHelper {
private final ProcessingEnvironment env;
private final Types types;
TypeUtils(ProcessingEnvironment env) {
public TypeHelper(ProcessingEnvironment env) {
this.env = env;
this.types = env.getTypeUtils();
}
public String getType(Element element) {
return getType(element != null ? element.asType() : null);
}

View File

@ -1,20 +0,0 @@
/*
* Copyright 2002-2016 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.
*/
/**
* Support package for defining and storing the metadata that forms the index.
*/
package org.springframework.context.index.metadata;

View File

@ -1,21 +0,0 @@
/*
* Copyright 2002-2016 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.
*/
/**
* Generates a 'META-INF/spring.candidates' at compilation time with all
* the component candidates detected in the module.
*/
package org.springframework.context.index;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -32,8 +32,6 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.springframework.context.index.metadata.CandidateComponentsMetadata;
import org.springframework.context.index.metadata.PropertiesMarshaller;
import org.springframework.context.index.sample.AbstractController;
import org.springframework.context.index.sample.MetaControllerIndexed;
import org.springframework.context.index.sample.SampleComponent;
@ -49,10 +47,10 @@ import org.springframework.context.index.sample.jpa.SampleConverter;
import org.springframework.context.index.sample.jpa.SampleEmbeddable;
import org.springframework.context.index.sample.jpa.SampleEntity;
import org.springframework.context.index.sample.jpa.SampleMappedSuperClass;
import org.springframework.context.index.sample.type.Repo;
import org.springframework.context.index.sample.type.SampleRepo;
import org.springframework.context.index.sample.type.SampleSmartRepo;
import org.springframework.context.index.sample.type.SampleSpecializedRepo;
import org.springframework.context.index.sample.type.Repo;
import org.springframework.context.index.sample.type.SmartRepo;
import org.springframework.context.index.sample.type.SpecializedRepo;
import org.springframework.context.index.test.TestCompiler;
@ -60,7 +58,7 @@ import org.springframework.stereotype.Component;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.context.index.test.Metadata.*;
import static org.springframework.context.index.Metadata.*;
/**
* Tests for {@link CandidateComponentsIndexer}.
@ -69,19 +67,21 @@ import static org.springframework.context.index.test.Metadata.*;
*/
public class CandidateComponentsIndexerTests {
private TestCompiler compiler;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
private TestCompiler compiler;
@Before
public void createCompiler() throws IOException {
this.compiler = new TestCompiler(this.temporaryFolder);
}
@Test
public void noCandidate() throws IOException {
CandidateComponentsMetadata metadata = compile(SampleNone.class);
@ -230,15 +230,14 @@ public class CandidateComponentsIndexerTests {
File metadataFile = new File(outputLocation,
MetadataStore.METADATA_PATH);
if (metadataFile.isFile()) {
return new PropertiesMarshaller()
.read(new FileInputStream(metadataFile));
return PropertiesMarshaller.read(new FileInputStream(metadataFile));
}
else {
return new CandidateComponentsMetadata();
}
}
catch (IOException e) {
throw new RuntimeException("Failed to read metadata from disk", e);
catch (IOException ex) {
throw new IllegalStateException("Failed to read metadata from disk", ex);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.index.test;
package org.springframework.context.index;
import java.util.Arrays;
import java.util.List;
@ -23,9 +23,6 @@ import java.util.stream.Collectors;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.springframework.context.index.metadata.ItemMetadata;
import org.springframework.context.index.metadata.CandidateComponentsMetadata;
/**
* Hamcrest {@link org.hamcrest.Matcher Matcher} to help test {@link CandidateComponentsMetadata}.
*
@ -41,6 +38,7 @@ public class Metadata {
return new ItemMetadataMatcher(type, stereotypes);
}
private static class ItemMetadataMatcher extends BaseMatcher<CandidateComponentsMetadata> {
private final String type;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.context.index.metadata;
package org.springframework.context.index;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -26,7 +26,7 @@ import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.context.index.test.Metadata.*;
import static org.springframework.context.index.Metadata.*;
/**
* Tests for {@link PropertiesMarshaller}.
@ -42,9 +42,8 @@ public class PropertiesMarshallerTests {
metadata.add(createItem("com.bar", "first"));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PropertiesMarshaller marshaller = new PropertiesMarshaller();
marshaller.write(metadata, outputStream);
CandidateComponentsMetadata readMetadata = marshaller.read(
PropertiesMarshaller.write(metadata, outputStream);
CandidateComponentsMetadata readMetadata = PropertiesMarshaller.read(
new ByteArrayInputStream(outputStream.toByteArray()));
assertThat(readMetadata, hasComponent("com.foo", "first", "second"));
assertThat(readMetadata, hasComponent("com.bar", "first"));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -46,12 +46,12 @@ public class TestCompiler {
private final File outputLocation;
public TestCompiler(TemporaryFolder temporaryFolder) throws IOException {
this(ToolProvider.getSystemJavaCompiler(), temporaryFolder);
}
public TestCompiler(JavaCompiler compiler, TemporaryFolder temporaryFolder)
throws IOException {
public TestCompiler(JavaCompiler compiler, TemporaryFolder temporaryFolder) throws IOException {
this.compiler = compiler;
this.fileManager = compiler.getStandardFileManager(null, null, null);
this.outputLocation = temporaryFolder.newFolder();
@ -60,6 +60,7 @@ public class TestCompiler {
this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, temp);
}
public TestCompilationTask getTask(Class<?>... types) {
List<String> names = Arrays.stream(types).map(Class::getName)
.collect(Collectors.toList());
@ -101,6 +102,7 @@ public class TestCompiler {
return ORIGINAL_SOURCE_FOLDER;
}
/**
* A compilation task.
*/
@ -121,4 +123,4 @@ public class TestCompiler {
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -28,8 +28,8 @@ import org.springframework.util.MultiValueMap;
/**
* Provide access to the candidates that are defined in {@code META-INF/spring.components}.
* <p>
* An arbitrary number of stereotypes can be registered (and queried) on the index: a
*
* <p>An arbitrary number of stereotypes can be registered (and queried) on the index: a
* typical example is the fully qualified name of an annotation that flags the class for
* a certain use case. The following call returns all the {@code @Component}
* <b>candidate</b> types for the {@code com.example} package (and its sub-packages):
@ -38,7 +38,7 @@ import org.springframework.util.MultiValueMap;
* "com.example", "org.springframework.stereotype.Component");
* </pre>
*
* The {@code type} is usually the fully qualified name of a class, though this is
* <p>The {@code type} is usually the fully qualified name of a class, though this is
* not a rule. Similarly, the {@code stereotype} is usually the fully qualified name of
* a target type but it can be any marker really.
*
@ -49,10 +49,12 @@ public class CandidateComponentsIndex {
private final MultiValueMap<String, String> index;
CandidateComponentsIndex(List<Properties> content) {
this.index = parseIndex(content);
}
/**
* Return the candidate types that are associated with the specified stereotype.
* @param basePackage the package to check for candidates

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -87,6 +87,7 @@ public class CandidateComponentsIndexLoader {
if (shouldIgnoreIndex) {
return null;
}
try {
Enumeration<URL> urls = classLoader.getResources(COMPONENTS_RESOURCE_LOCATION);
if (!urls.hasMoreElements()) {
@ -98,14 +99,14 @@ public class CandidateComponentsIndexLoader {
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
result.add(properties);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + result.size() + "] index(es)");
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + result.size() + "] index(es)");
}
int totalCount = result.stream().mapToInt(Properties::size).sum();
return (totalCount > 0 ? new CandidateComponentsIndex(result) : null);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load indexes from location [" +
throw new IllegalStateException("Unable to load indexes from location [" +
COMPONENTS_RESOURCE_LOCATION + "]", ex);
}
}

View File

@ -1,20 +1,4 @@
/*
* Copyright 2002-2016 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.
*/
/**
* Support package for reading and managing the components index.
*/
package org.springframework.context.index;
package org.springframework.context.index;