Add TypeExcludeFilters support
Provide a way for auto-configuration tests to easily filter scanned components. See gh-4901
This commit is contained in:
@@ -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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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 @@
|
||||
/*
|
||||
* 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;
|
||||
@@ -1,6 +1,7 @@
|
||||
# Spring Test ContextCustomizerFactories
|
||||
org.springframework.test.context.ContextCustomizerFactory=\
|
||||
org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory,\
|
||||
org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizerFactory,\
|
||||
org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizerFactory
|
||||
|
||||
# Test Execution Listeners
|
||||
|
||||
@@ -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 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user