001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.test.autoconfigure.filter; 018 019import java.io.IOException; 020import java.lang.annotation.Annotation; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.Iterator; 024import java.util.List; 025import java.util.regex.Pattern; 026 027import org.springframework.beans.BeanUtils; 028import org.springframework.context.annotation.ComponentScan.Filter; 029import org.springframework.context.annotation.FilterType; 030import org.springframework.core.type.classreading.MetadataReader; 031import org.springframework.core.type.classreading.MetadataReaderFactory; 032import org.springframework.core.type.filter.AnnotationTypeFilter; 033import org.springframework.core.type.filter.AspectJTypeFilter; 034import org.springframework.core.type.filter.AssignableTypeFilter; 035import org.springframework.core.type.filter.RegexPatternTypeFilter; 036import org.springframework.core.type.filter.TypeFilter; 037import org.springframework.util.Assert; 038 039/** 040 * Utility to load {@link TypeFilter TypeFilters} from {@link Filter @Filter} annotations. 041 * 042 * @author Phillip Webb 043 * @since 1.4.0 044 */ 045public class FilterAnnotations implements Iterable<TypeFilter> { 046 047 private final ClassLoader classLoader; 048 049 private final List<TypeFilter> filters; 050 051 public FilterAnnotations(ClassLoader classLoader, Filter[] filters) { 052 Assert.notNull(filters, "Filters must not be null"); 053 this.classLoader = classLoader; 054 this.filters = createTypeFilters(filters); 055 } 056 057 private List<TypeFilter> createTypeFilters(Filter[] filters) { 058 List<TypeFilter> typeFilters = new ArrayList<>(); 059 for (Filter filter : filters) { 060 for (Class<?> filterClass : filter.classes()) { 061 typeFilters.add(createTypeFilter(filter.type(), filterClass)); 062 } 063 for (String pattern : filter.pattern()) { 064 typeFilters.add(createTypeFilter(filter.type(), pattern)); 065 } 066 } 067 return Collections.unmodifiableList(typeFilters); 068 } 069 070 @SuppressWarnings("unchecked") 071 private TypeFilter createTypeFilter(FilterType filterType, Class<?> filterClass) { 072 switch (filterType) { 073 case ANNOTATION: 074 Assert.isAssignable(Annotation.class, filterClass, 075 "An error occurred while processing an ANNOTATION type filter: "); 076 return new AnnotationTypeFilter((Class<Annotation>) filterClass); 077 case ASSIGNABLE_TYPE: 078 return new AssignableTypeFilter(filterClass); 079 case CUSTOM: 080 Assert.isAssignable(TypeFilter.class, filterClass, 081 "An error occurred while processing a CUSTOM type filter: "); 082 return BeanUtils.instantiateClass(filterClass, TypeFilter.class); 083 } 084 throw new IllegalArgumentException( 085 "Filter type not supported with Class value: " + filterType); 086 } 087 088 private TypeFilter createTypeFilter(FilterType filterType, String pattern) { 089 switch (filterType) { 090 case ASPECTJ: 091 return new AspectJTypeFilter(pattern, this.classLoader); 092 case REGEX: 093 return new RegexPatternTypeFilter(Pattern.compile(pattern)); 094 } 095 throw new IllegalArgumentException( 096 "Filter type not supported with String pattern: " + filterType); 097 } 098 099 @Override 100 public Iterator<TypeFilter> iterator() { 101 return this.filters.iterator(); 102 } 103 104 public boolean anyMatches(MetadataReader metadataReader, 105 MetadataReaderFactory metadataReaderFactory) throws IOException { 106 for (TypeFilter filter : this) { 107 if (filter.match(metadataReader, metadataReaderFactory)) { 108 return true; 109 } 110 } 111 return false; 112 } 113 114}