001/* 002 * Copyright 2002-2019 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 * https://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.core.type.filter; 018 019import java.io.IOException; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.core.type.ClassMetadata; 025import org.springframework.core.type.classreading.MetadataReader; 026import org.springframework.core.type.classreading.MetadataReaderFactory; 027import org.springframework.lang.Nullable; 028 029/** 030 * Type filter that is aware of traversing over hierarchy. 031 * 032 * <p>This filter is useful when matching needs to be made based on potentially the 033 * whole class/interface hierarchy. The algorithm employed uses a succeed-fast 034 * strategy: if at any time a match is declared, no further processing is 035 * carried out. 036 * 037 * @author Ramnivas Laddad 038 * @author Mark Fisher 039 * @since 2.5 040 */ 041public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter { 042 043 protected final Log logger = LogFactory.getLog(getClass()); 044 045 private final boolean considerInherited; 046 047 private final boolean considerInterfaces; 048 049 050 protected AbstractTypeHierarchyTraversingFilter(boolean considerInherited, boolean considerInterfaces) { 051 this.considerInherited = considerInherited; 052 this.considerInterfaces = considerInterfaces; 053 } 054 055 056 @Override 057 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) 058 throws IOException { 059 060 // This method optimizes avoiding unnecessary creation of ClassReaders 061 // as well as visiting over those readers. 062 if (matchSelf(metadataReader)) { 063 return true; 064 } 065 ClassMetadata metadata = metadataReader.getClassMetadata(); 066 if (matchClassName(metadata.getClassName())) { 067 return true; 068 } 069 070 if (this.considerInherited) { 071 String superClassName = metadata.getSuperClassName(); 072 if (superClassName != null) { 073 // Optimization to avoid creating ClassReader for super class. 074 Boolean superClassMatch = matchSuperClass(superClassName); 075 if (superClassMatch != null) { 076 if (superClassMatch.booleanValue()) { 077 return true; 078 } 079 } 080 else { 081 // Need to read super class to determine a match... 082 try { 083 if (match(metadata.getSuperClassName(), metadataReaderFactory)) { 084 return true; 085 } 086 } 087 catch (IOException ex) { 088 if (logger.isDebugEnabled()) { 089 logger.debug("Could not read super class [" + metadata.getSuperClassName() + 090 "] of type-filtered class [" + metadata.getClassName() + "]"); 091 } 092 } 093 } 094 } 095 } 096 097 if (this.considerInterfaces) { 098 for (String ifc : metadata.getInterfaceNames()) { 099 // Optimization to avoid creating ClassReader for super class 100 Boolean interfaceMatch = matchInterface(ifc); 101 if (interfaceMatch != null) { 102 if (interfaceMatch.booleanValue()) { 103 return true; 104 } 105 } 106 else { 107 // Need to read interface to determine a match... 108 try { 109 if (match(ifc, metadataReaderFactory)) { 110 return true; 111 } 112 } 113 catch (IOException ex) { 114 if (logger.isDebugEnabled()) { 115 logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" + 116 metadata.getClassName() + "]"); 117 } 118 } 119 } 120 } 121 } 122 123 return false; 124 } 125 126 private boolean match(String className, MetadataReaderFactory metadataReaderFactory) throws IOException { 127 return match(metadataReaderFactory.getMetadataReader(className), metadataReaderFactory); 128 } 129 130 /** 131 * Override this to match self characteristics alone. Typically, 132 * the implementation will use a visitor to extract information 133 * to perform matching. 134 */ 135 protected boolean matchSelf(MetadataReader metadataReader) { 136 return false; 137 } 138 139 /** 140 * Override this to match on type name. 141 */ 142 protected boolean matchClassName(String className) { 143 return false; 144 } 145 146 /** 147 * Override this to match on super type name. 148 */ 149 @Nullable 150 protected Boolean matchSuperClass(String superClassName) { 151 return null; 152 } 153 154 /** 155 * Override this to match on interface type name. 156 */ 157 @Nullable 158 protected Boolean matchInterface(String interfaceName) { 159 return null; 160 } 161 162}