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