Browse Source
Provide a way for auto-configuration tests to easily filter scanned components. See gh-4901pull/5488/head
9 changed files with 755 additions and 0 deletions
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.annotation.Annotation; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware; |
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
import org.springframework.context.annotation.ComponentScan.Filter; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.core.type.filter.AnnotationTypeFilter; |
||||
import org.springframework.core.type.filter.AssignableTypeFilter; |
||||
|
||||
/** |
||||
* Abstract base class for a {@link TypeExcludeFilter} that can be customized using an |
||||
* annotation. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 1.4.0 |
||||
*/ |
||||
public abstract class AnnotationCustomizableTypeExcludeFilter extends TypeExcludeFilter |
||||
implements BeanClassLoaderAware { |
||||
|
||||
private ClassLoader classLoader; |
||||
|
||||
@Override |
||||
public void setBeanClassLoader(ClassLoader classLoader) { |
||||
this.classLoader = classLoader; |
||||
} |
||||
|
||||
@Override |
||||
public boolean match(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
if (hasAnnotation()) { |
||||
return !(include(metadataReader, metadataReaderFactory) |
||||
&& !exclude(metadataReader, metadataReaderFactory)); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
protected boolean include(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
if (new FilterAnnotations(this.classLoader, getFilters(FilterType.INCLUDE)) |
||||
.anyMatches(metadataReader, metadataReaderFactory)) { |
||||
return true; |
||||
} |
||||
if (isUseDefaultFilters() |
||||
&& defaultInclude(metadataReader, metadataReaderFactory)) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
protected boolean defaultInclude(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
for (Class<?> include : getDefaultIncudes()) { |
||||
if (isTypeOrAnnotated(metadataReader, metadataReaderFactory, include)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
protected boolean exclude(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
return new FilterAnnotations(this.classLoader, getFilters(FilterType.EXCLUDE)) |
||||
.anyMatches(metadataReader, metadataReaderFactory); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
protected final boolean isTypeOrAnnotated(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory, Class<?> type) |
||||
throws IOException { |
||||
AnnotationTypeFilter annotationFilter = new AnnotationTypeFilter( |
||||
(Class<? extends Annotation>) type); |
||||
AssignableTypeFilter typeFilter = new AssignableTypeFilter(type); |
||||
return annotationFilter.match(metadataReader, metadataReaderFactory) |
||||
|| typeFilter.match(metadataReader, metadataReaderFactory); |
||||
} |
||||
|
||||
protected abstract boolean hasAnnotation(); |
||||
|
||||
protected abstract Filter[] getFilters(FilterType type); |
||||
|
||||
protected abstract boolean isUseDefaultFilters(); |
||||
|
||||
protected abstract Set<Class<?>> getDefaultIncudes(); |
||||
|
||||
protected static enum FilterType { |
||||
INCLUDE, EXCLUDE |
||||
}; |
||||
|
||||
} |
||||
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.annotation.Annotation; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import org.springframework.beans.BeanUtils; |
||||
import org.springframework.context.annotation.ComponentScan.Filter; |
||||
import org.springframework.context.annotation.FilterType; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.core.type.filter.AnnotationTypeFilter; |
||||
import org.springframework.core.type.filter.AspectJTypeFilter; |
||||
import org.springframework.core.type.filter.AssignableTypeFilter; |
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter; |
||||
import org.springframework.core.type.filter.TypeFilter; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Utility to load {@link TypeFilter TypeFilters} from {@link Filter @Filter} annotations. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 1.4.0 |
||||
*/ |
||||
public class FilterAnnotations implements Iterable<TypeFilter> { |
||||
|
||||
private final ClassLoader classLoader; |
||||
|
||||
private final List<TypeFilter> filters; |
||||
|
||||
public FilterAnnotations(ClassLoader classLoader, Filter[] filters) { |
||||
Assert.notNull(filters, "Filters must not be null"); |
||||
this.classLoader = classLoader; |
||||
this.filters = createTypeFilters(filters); |
||||
} |
||||
|
||||
private List<TypeFilter> createTypeFilters(Filter[] filters) { |
||||
List<TypeFilter> typeFilters = new ArrayList<TypeFilter>(); |
||||
for (Filter filter : filters) { |
||||
for (Class<?> filterClass : filter.classes()) { |
||||
typeFilters.add(createTypeFilter(filter.type(), filterClass)); |
||||
} |
||||
for (String pattern : filter.pattern()) { |
||||
typeFilters.add(createTypeFilter(filter.type(), pattern)); |
||||
} |
||||
} |
||||
return Collections.unmodifiableList(typeFilters); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private TypeFilter createTypeFilter(FilterType filterType, Class<?> filterClass) { |
||||
switch (filterType) { |
||||
case ANNOTATION: |
||||
Assert.isAssignable(Annotation.class, filterClass, |
||||
"An error occured while processing a ANNOTATION type filter: "); |
||||
return new AnnotationTypeFilter((Class<Annotation>) filterClass); |
||||
case ASSIGNABLE_TYPE: |
||||
return new AssignableTypeFilter(filterClass); |
||||
case CUSTOM: |
||||
Assert.isAssignable(TypeFilter.class, filterClass, |
||||
"An error occured while processing a CUSTOM type filter: "); |
||||
return BeanUtils.instantiateClass(filterClass, TypeFilter.class); |
||||
} |
||||
throw new IllegalArgumentException( |
||||
"Filter type not supported with Class value: " + filterType); |
||||
} |
||||
|
||||
private TypeFilter createTypeFilter(FilterType filterType, String pattern) { |
||||
switch (filterType) { |
||||
case ASPECTJ: |
||||
return new AspectJTypeFilter(pattern, this.classLoader); |
||||
case REGEX: |
||||
return new RegexPatternTypeFilter(Pattern.compile(pattern)); |
||||
} |
||||
throw new IllegalArgumentException( |
||||
"Filter type not supported with String pattern: " + filterType); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<TypeFilter> iterator() { |
||||
return this.filters.iterator(); |
||||
} |
||||
|
||||
public boolean anyMatches(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
for (TypeFilter filter : this) { |
||||
if (filter.match(metadataReader, metadataReaderFactory)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
|
||||
/** |
||||
* Annotation that can on tests to define a set of {@link TypeExcludeFilter } classes that |
||||
* should be applied to {@link SpringBootApplication @SpringBootApplication} component |
||||
* scanning. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 1.4.0 |
||||
* @see TypeExcludeFilter |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
public @interface TypeExcludeFilters { |
||||
|
||||
/** |
||||
* Specifies {@link TypeExcludeFilter} classes that should be applied to |
||||
* {@link SpringBootApplication @SpringBootApplication} component scanning. Classes |
||||
* specified here can either have a no-arg constructor or accept a single |
||||
* {@code Class<?>} argument if then need access to the {@code testClass}. |
||||
* @see TypeExcludeFilter |
||||
*/ |
||||
Class<? extends TypeExcludeFilter>[] value(); |
||||
|
||||
} |
||||
@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Constructor; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.test.context.ContextCustomizer; |
||||
import org.springframework.test.context.MergedContextConfiguration; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* {@link ContextCustomizer} to support {@link TypeExcludeFilters @TypeExcludeFilters}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @see TypeExcludeFilters |
||||
*/ |
||||
class TypeExcludeFiltersContextCustomizer implements ContextCustomizer { |
||||
|
||||
private static final String EXCLUDE_FILTER_BEAN_NAME = TypeExcludeFilters.class |
||||
.getName(); |
||||
|
||||
private final Class<?> testClass; |
||||
|
||||
private final Set<Class<? extends TypeExcludeFilter>> filterClasses; |
||||
|
||||
TypeExcludeFiltersContextCustomizer(Class<?> testClass, |
||||
Set<Class<? extends TypeExcludeFilter>> filterClasses) { |
||||
this.testClass = testClass; |
||||
this.filterClasses = filterClasses; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return this.filterClasses.hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
return (obj != null && getClass().equals(obj.getClass()) && this.filterClasses |
||||
.equals(((TypeExcludeFiltersContextCustomizer) obj).filterClasses)); |
||||
} |
||||
|
||||
@Override |
||||
public void customizeContext(ConfigurableApplicationContext context, |
||||
MergedContextConfiguration mergedContextConfiguration) { |
||||
if (!this.filterClasses.isEmpty()) { |
||||
context.getBeanFactory().registerSingleton(EXCLUDE_FILTER_BEAN_NAME, |
||||
createDelegatingTypeExcludeFilter()); |
||||
} |
||||
} |
||||
|
||||
private TypeExcludeFilter createDelegatingTypeExcludeFilter() { |
||||
final Set<TypeExcludeFilter> filters = new LinkedHashSet<TypeExcludeFilter>( |
||||
this.filterClasses.size()); |
||||
for (Class<? extends TypeExcludeFilter> filterClass : this.filterClasses) { |
||||
filters.add(createTypeExcludeFilter(filterClass)); |
||||
} |
||||
return new TypeExcludeFilter() { |
||||
|
||||
@Override |
||||
public boolean match(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
for (TypeExcludeFilter filter : filters) { |
||||
if (filter.match(metadataReader, metadataReaderFactory)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
}; |
||||
} |
||||
|
||||
private TypeExcludeFilter createTypeExcludeFilter(Class<?> type) { |
||||
try { |
||||
Constructor<?> constructor = getTypeExcludeFilterConstructor(type); |
||||
ReflectionUtils.makeAccessible(constructor); |
||||
if (constructor.getParameterTypes().length == 1) { |
||||
return (TypeExcludeFilter) constructor.newInstance(this.testClass); |
||||
} |
||||
return (TypeExcludeFilter) constructor.newInstance(); |
||||
} |
||||
catch (Exception ex) { |
||||
throw new IllegalStateException("Unable to create filter for " + type, ex); |
||||
} |
||||
} |
||||
|
||||
private Constructor<?> getTypeExcludeFilterConstructor(Class<?> type) |
||||
throws NoSuchMethodException { |
||||
try { |
||||
return type.getDeclaredConstructor(Class.class); |
||||
} |
||||
catch (Exception ex) { |
||||
return type.getDeclaredConstructor(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
import org.springframework.core.annotation.AnnotatedElementUtils; |
||||
import org.springframework.test.context.ContextConfigurationAttributes; |
||||
import org.springframework.test.context.ContextCustomizer; |
||||
import org.springframework.test.context.ContextCustomizerFactory; |
||||
|
||||
/** |
||||
* {@link ContextCustomizerFactory} to support |
||||
* {@link TypeExcludeFilters @TypeExcludeFilters}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @see TypeExcludeFiltersContextCustomizer |
||||
*/ |
||||
class TypeExcludeFiltersContextCustomizerFactory implements ContextCustomizerFactory { |
||||
|
||||
@Override |
||||
public ContextCustomizer createContextCustomizer(Class<?> testClass, |
||||
List<ContextConfigurationAttributes> configurationAttributes) { |
||||
TypeExcludeFilters annotation = AnnotatedElementUtils |
||||
.findMergedAnnotation(testClass, TypeExcludeFilters.class); |
||||
if (annotation != null) { |
||||
Set<Class<? extends TypeExcludeFilter>> filterClasses = new LinkedHashSet<Class<? extends TypeExcludeFilter>>( |
||||
Arrays.asList(annotation.value())); |
||||
return new TypeExcludeFiltersContextCustomizer(testClass, filterClasses); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
/** |
||||
* Helper utilities for using {@link org.springframework.boot.context.TypeExcludeFilter} |
||||
* with auto-configured tests. |
||||
*/ |
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter; |
||||
import org.springframework.context.annotation.FilterType; |
||||
import org.springframework.core.annotation.AnnotatedElementUtils; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; |
||||
import org.springframework.core.type.filter.TypeFilter; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link FilterAnnotations}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class FilterAnnotationsTests { |
||||
|
||||
@Test |
||||
public void filterAnnotation() throws Exception { |
||||
FilterAnnotations filterAnnotations = get(FilterByAnnotation.class); |
||||
assertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isTrue(); |
||||
assertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
public void filterAssignableType() throws Exception { |
||||
FilterAnnotations filterAnnotations = get(FilterByType.class); |
||||
assertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse(); |
||||
assertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void filterCustom() throws Exception { |
||||
FilterAnnotations filterAnnotations = get(FilterByCustom.class); |
||||
assertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse(); |
||||
assertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void filterAspectJ() throws Exception { |
||||
FilterAnnotations filterAnnotations = get(FilterByAspectJ.class); |
||||
assertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse(); |
||||
assertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void filterRegex() throws Exception { |
||||
FilterAnnotations filterAnnotations = get(FilterByRegex.class); |
||||
assertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse(); |
||||
assertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
public void anyMatches() throws Exception { |
||||
} |
||||
|
||||
private FilterAnnotations get(Class<?> type) { |
||||
Filters filters = AnnotatedElementUtils.getMergedAnnotation(type, Filters.class); |
||||
return new FilterAnnotations(getClass().getClassLoader(), filters.value()); |
||||
} |
||||
|
||||
private boolean match(FilterAnnotations filterAnnotations, Class<?> type) |
||||
throws IOException { |
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); |
||||
MetadataReader metadataReader = metadataReaderFactory |
||||
.getMetadataReader(type.getName()); |
||||
return filterAnnotations.anyMatches(metadataReader, metadataReaderFactory); |
||||
} |
||||
|
||||
@Filters(@Filter(Service.class)) |
||||
static class FilterByAnnotation { |
||||
|
||||
} |
||||
|
||||
@Filters(@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ExampleWithoutAnnotation.class)) |
||||
static class FilterByType { |
||||
|
||||
} |
||||
|
||||
@Filters(@Filter(type = FilterType.CUSTOM, classes = ExampleCustomFilter.class)) |
||||
static class FilterByCustom { |
||||
|
||||
} |
||||
|
||||
@Filters(@Filter(type = FilterType.ASPECTJ, pattern = "(*..*ExampleWithoutAnnotation)")) |
||||
static class FilterByAspectJ { |
||||
|
||||
} |
||||
|
||||
@Filters(@Filter(type = FilterType.REGEX, pattern = ".*ExampleWithoutAnnotation")) |
||||
static class FilterByRegex { |
||||
|
||||
} |
||||
|
||||
@Target({ ElementType.TYPE }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
static @interface Filters { |
||||
|
||||
Filter[] value(); |
||||
|
||||
} |
||||
|
||||
static class ExampleCustomFilter implements TypeFilter { |
||||
|
||||
@Override |
||||
public boolean match(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
return metadataReader.getClassMetadata().getClassName() |
||||
.equals(ExampleWithoutAnnotation.class.getName()); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Service |
||||
static class ExampleWithAnnotation { |
||||
|
||||
} |
||||
|
||||
static class ExampleWithoutAnnotation { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
/* |
||||
* Copyright 2012-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. |
||||
*/ |
||||
|
||||
package org.springframework.boot.test.autoconfigure.filter; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.context.TypeExcludeFilter; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; |
||||
import org.springframework.test.context.ContextCustomizer; |
||||
import org.springframework.test.context.MergedContextConfiguration; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link TypeExcludeFiltersContextCustomizerFactory}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class TypeExcludeFiltersTestContextCustomizerFactoryTests { |
||||
|
||||
private TypeExcludeFiltersContextCustomizerFactory factory = new TypeExcludeFiltersContextCustomizerFactory(); |
||||
|
||||
private MergedContextConfiguration mergedContextConfiguration = mock( |
||||
MergedContextConfiguration.class); |
||||
|
||||
private ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); |
||||
|
||||
@Test |
||||
public void getContextCustomizerWhenHasNoAnnotationShouldReturnNull() |
||||
throws Exception { |
||||
ContextCustomizer customizer = this.factory |
||||
.createContextCustomizer(NoAnnotation.class, null); |
||||
assertThat(customizer).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void getContextCustomizerWhenHasAnnotationShouldReturnCustomizer() |
||||
throws Exception { |
||||
ContextCustomizer customizer = this.factory |
||||
.createContextCustomizer(WithExcludeFilters.class, null); |
||||
assertThat(customizer).isNotNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void hashCodeAndEquals() throws Exception { |
||||
ContextCustomizer customizer1 = this.factory |
||||
.createContextCustomizer(WithExcludeFilters.class, null); |
||||
ContextCustomizer customizer2 = this.factory |
||||
.createContextCustomizer(WithSameExcludeFilters.class, null); |
||||
ContextCustomizer customizer3 = this.factory |
||||
.createContextCustomizer(WithDifferentExcludeFilters.class, null); |
||||
assertThat(customizer1.hashCode()).isEqualTo(customizer2.hashCode()); |
||||
assertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2) |
||||
.isNotEqualTo(customizer3); |
||||
} |
||||
|
||||
@Test |
||||
public void getContextCustomizerShouldAddExcludeFilters() throws Exception { |
||||
ContextCustomizer customizer = this.factory |
||||
.createContextCustomizer(WithExcludeFilters.class, null); |
||||
customizer.customizeContext(this.context, this.mergedContextConfiguration); |
||||
this.context.refresh(); |
||||
TypeExcludeFilter filter = this.context.getBean(TypeExcludeFilter.class); |
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); |
||||
MetadataReader metadataReader = metadataReaderFactory |
||||
.getMetadataReader(NoAnnotation.class.getName()); |
||||
assertThat(filter.match(metadataReader, metadataReaderFactory)).isFalse(); |
||||
metadataReader = metadataReaderFactory |
||||
.getMetadataReader(SimpleExclude.class.getName()); |
||||
assertThat(filter.match(metadataReader, metadataReaderFactory)).isTrue(); |
||||
metadataReader = metadataReaderFactory |
||||
.getMetadataReader(TestClassAwareExclude.class.getName()); |
||||
assertThat(filter.match(metadataReader, metadataReaderFactory)).isTrue(); |
||||
} |
||||
|
||||
static class NoAnnotation { |
||||
|
||||
} |
||||
|
||||
@TypeExcludeFilters({ SimpleExclude.class, TestClassAwareExclude.class }) |
||||
static class WithExcludeFilters { |
||||
|
||||
} |
||||
|
||||
@TypeExcludeFilters({ TestClassAwareExclude.class, SimpleExclude.class }) |
||||
static class WithSameExcludeFilters { |
||||
|
||||
} |
||||
|
||||
@TypeExcludeFilters(SimpleExclude.class) |
||||
static class WithDifferentExcludeFilters { |
||||
|
||||
} |
||||
|
||||
static class SimpleExclude extends TypeExcludeFilter { |
||||
|
||||
@Override |
||||
public boolean match(MetadataReader metadataReader, |
||||
MetadataReaderFactory metadataReaderFactory) throws IOException { |
||||
return metadataReader.getClassMetadata().getClassName() |
||||
.equals(getClass().getName()); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class TestClassAwareExclude extends SimpleExclude { |
||||
|
||||
TestClassAwareExclude(Class<?> testClass) { |
||||
assertThat(testClass).isEqualTo(WithExcludeFilters.class); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue