Merge branch '1.5.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-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,6 +18,7 @@ package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.boot.context.annotation.DeterminableImports;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -122,12 +124,52 @@ public abstract class AutoConfigurationPackages {
|
||||
* configuration.
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
static class Registrar implements ImportBeanDefinitionRegistrar {
|
||||
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
register(registry, ClassUtils.getPackageName(metadata.getClassName()));
|
||||
register(registry, new PackageImport(metadata).getPackageName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Object> determineImports(AnnotationMetadata metadata) {
|
||||
return Collections.<Object>singleton(new PackageImport(metadata));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for a package import.
|
||||
*/
|
||||
private final static class PackageImport {
|
||||
|
||||
private final String packageName;
|
||||
|
||||
PackageImport(AnnotationMetadata metadata) {
|
||||
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.packageName.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
return this.packageName.equals(((PackageImport) obj).packageName);
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return this.packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Package Import " + this.packageName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.context.annotation.DeterminableImports;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -44,7 +45,8 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
|
||||
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector
|
||||
implements DeterminableImports {
|
||||
|
||||
private static final Set<String> ANNOTATION_NAMES;
|
||||
|
||||
@@ -55,6 +57,14 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
ANNOTATION_NAMES = Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Object> determineImports(AnnotationMetadata metadata) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
result.addAll(getCandidateConfigurations(metadata, null));
|
||||
result.removeAll(getExclusions(metadata, null));
|
||||
return Collections.<Object>unmodifiableSet(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
|
||||
return null;
|
||||
@@ -85,6 +95,10 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
if (classes.length > 0) {
|
||||
return Arrays.asList(classes);
|
||||
}
|
||||
return loadFactoryNames(source);
|
||||
}
|
||||
|
||||
protected Collection<String> loadFactoryNames(Class<?> source) {
|
||||
return SpringFactoriesLoader.loadFactoryNames(source,
|
||||
getClass().getClassLoader());
|
||||
}
|
||||
@@ -117,7 +131,8 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
return exclusions;
|
||||
}
|
||||
|
||||
private Map<Class<?>, List<Annotation>> getAnnotations(AnnotationMetadata metadata) {
|
||||
protected final Map<Class<?>, List<Annotation>> getAnnotations(
|
||||
AnnotationMetadata metadata) {
|
||||
MultiValueMap<Class<?>, Annotation> annotations = new LinkedMultiValueMap<Class<?>, Annotation>();
|
||||
Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
|
||||
collectAnnotations(source, annotations, new HashSet<Class<?>>());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
@@ -19,6 +19,9 @@ package org.springframework.boot.autoconfigure;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -46,7 +49,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
*/
|
||||
public class ImportAutoConfigurationImportSelectorTests {
|
||||
|
||||
private final ImportAutoConfigurationImportSelector importSelector = new ImportAutoConfigurationImportSelector();
|
||||
private final ImportAutoConfigurationImportSelector importSelector = new TestImportAutoConfigurationImportSelector();
|
||||
|
||||
private final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
|
||||
@@ -63,36 +66,32 @@ public class ImportAutoConfigurationImportSelectorTests {
|
||||
|
||||
@Test
|
||||
public void importsAreSelected() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(ImportFreeMarker.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ImportFreeMarker.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsExactly(FreeMarkerAutoConfiguration.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importsAreSelectedUsingClassesAttribute() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(ImportFreeMarkerUsingClassesAttribute.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ImportFreeMarkerUsingClassesAttribute.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsExactly(FreeMarkerAutoConfiguration.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyExclusionsAreNotApplied() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(ImportFreeMarker.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ImportFreeMarker.class);
|
||||
this.importSelector.selectImports(annotationMetadata);
|
||||
verifyZeroInteractions(this.environment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleImportsAreFound() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(MultipleImports.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
MultipleImports.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsOnly(FreeMarkerAutoConfiguration.class.getName(),
|
||||
ThymeleafAutoConfiguration.class.getName());
|
||||
@@ -100,41 +99,94 @@ public class ImportAutoConfigurationImportSelectorTests {
|
||||
|
||||
@Test
|
||||
public void selfAnnotatingAnnotationDoesNotCauseStackOverflow() throws IOException {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(ImportWithSelfAnnotatingAnnotation.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ImportWithSelfAnnotatingAnnotation.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsOnly(ThymeleafAutoConfiguration.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exclusionsAreApplied() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(MultipleImportsWithExclusion.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
MultipleImportsWithExclusion.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsOnly(FreeMarkerAutoConfiguration.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exclusionsWithoutImport() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(ExclusionWithoutImport.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ExclusionWithoutImport.class);
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).containsOnly(FreeMarkerAutoConfiguration.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exclusionsAliasesAreApplied() throws Exception {
|
||||
AnnotationMetadata annotationMetadata = new SimpleMetadataReaderFactory()
|
||||
.getMetadataReader(
|
||||
ImportWithSelfAnnotatingAnnotationExclude.class.getName())
|
||||
.getAnnotationMetadata();
|
||||
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
|
||||
ImportWithSelfAnnotatingAnnotationExclude.class);
|
||||
|
||||
String[] imports = this.importSelector.selectImports(annotationMetadata);
|
||||
assertThat(imports).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineImportsWhenUsingMetaWithoutClassesShouldBeEqual()
|
||||
throws Exception {
|
||||
Set<Object> set1 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedOne.class));
|
||||
Set<Object> set2 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedTwo.class));
|
||||
assertThat(set1).isEqualTo(set2);
|
||||
assertThat(set1.hashCode()).isEqualTo(set2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineImportsWhenUsingNonMetaWithoutClassesShouldBeSame()
|
||||
throws Exception {
|
||||
Set<Object> set1 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportAutoConfigurationWithUnrelatedOne.class));
|
||||
Set<Object> set2 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportAutoConfigurationWithUnrelatedTwo.class));
|
||||
assertThat(set1).isEqualTo(set2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineImportsWhenUsingNonMetaWithClassesShouldBeSame()
|
||||
throws Exception {
|
||||
Set<Object> set1 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportAutoConfigurationWithItemsOne.class));
|
||||
Set<Object> set2 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportAutoConfigurationWithItemsOne.class));
|
||||
assertThat(set1).isEqualTo(set2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineImportsWhenUsingMetaExcludeWithoutClassesShouldBeEqual()
|
||||
throws Exception {
|
||||
Set<Object> set1 = this.importSelector.determineImports(getAnnotationMetadata(
|
||||
ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));
|
||||
Set<Object> set2 = this.importSelector.determineImports(getAnnotationMetadata(
|
||||
ImportMetaAutoConfigurationExcludeWithUnrelatedTwo.class));
|
||||
assertThat(set1).isEqualTo(set2);
|
||||
assertThat(set1.hashCode()).isEqualTo(set2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineImportsWhenUsingMetaDifferentExcludeWithoutClassesShouldBeDifferent()
|
||||
throws Exception {
|
||||
Set<Object> set1 = this.importSelector.determineImports(getAnnotationMetadata(
|
||||
ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));
|
||||
Set<Object> set2 = this.importSelector.determineImports(
|
||||
getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedTwo.class));
|
||||
assertThat(set1).isNotEqualTo(set2);
|
||||
}
|
||||
|
||||
private AnnotationMetadata getAnnotationMetadata(Class<?> source) throws IOException {
|
||||
return new SimpleMetadataReaderFactory().getMetadataReader(source.getName())
|
||||
.getAnnotationMetadata();
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration(FreeMarkerAutoConfiguration.class)
|
||||
static class ImportFreeMarker {
|
||||
|
||||
@@ -186,6 +238,73 @@ public class ImportAutoConfigurationImportSelectorTests {
|
||||
|
||||
}
|
||||
|
||||
@MetaImportAutoConfiguration
|
||||
@UnrelatedOne
|
||||
static class ImportMetaAutoConfigurationWithUnrelatedOne {
|
||||
|
||||
}
|
||||
|
||||
@MetaImportAutoConfiguration
|
||||
@UnrelatedTwo
|
||||
static class ImportMetaAutoConfigurationWithUnrelatedTwo {
|
||||
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration
|
||||
@UnrelatedOne
|
||||
static class ImportAutoConfigurationWithUnrelatedOne {
|
||||
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration
|
||||
@UnrelatedTwo
|
||||
static class ImportAutoConfigurationWithUnrelatedTwo {
|
||||
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration(classes = ThymeleafAutoConfiguration.class)
|
||||
@UnrelatedOne
|
||||
static class ImportAutoConfigurationWithItemsOne {
|
||||
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration(classes = ThymeleafAutoConfiguration.class)
|
||||
@UnrelatedOne
|
||||
static class ImportAutoConfigurationWithItemsTwo {
|
||||
|
||||
}
|
||||
|
||||
@MetaImportAutoConfiguration(exclude = ThymeleafAutoConfiguration.class)
|
||||
@UnrelatedOne
|
||||
static class ImportMetaAutoConfigurationExcludeWithUnrelatedOne {
|
||||
|
||||
}
|
||||
|
||||
@MetaImportAutoConfiguration(exclude = ThymeleafAutoConfiguration.class)
|
||||
@UnrelatedTwo
|
||||
static class ImportMetaAutoConfigurationExcludeWithUnrelatedTwo {
|
||||
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface MetaImportAutoConfiguration {
|
||||
|
||||
@AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude")
|
||||
Class<?>[] exclude() default {};
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface UnrelatedOne {
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface UnrelatedTwo {
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ImportAutoConfiguration(ThymeleafAutoConfiguration.class)
|
||||
@SelfAnnotating
|
||||
@@ -196,4 +315,18 @@ public class ImportAutoConfigurationImportSelectorTests {
|
||||
|
||||
}
|
||||
|
||||
private static class TestImportAutoConfigurationImportSelector
|
||||
extends ImportAutoConfigurationImportSelector {
|
||||
|
||||
@Override
|
||||
protected Collection<String> loadFactoryNames(Class<?> source) {
|
||||
if (source == MetaImportAutoConfiguration.class) {
|
||||
return Arrays.asList(ThymeleafAutoConfiguration.class.getName(),
|
||||
FreeMarkerAutoConfiguration.class.getName());
|
||||
}
|
||||
return super.loadFactoryNames(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user