001/*
002 * Copyright 2002-2016 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 org.springframework.lang.Nullable;
020import org.springframework.util.ClassUtils;
021
022/**
023 * A simple filter which matches classes that are assignable to a given type.
024 *
025 * @author Rod Johnson
026 * @author Mark Fisher
027 * @author Ramnivas Laddad
028 * @since 2.5
029 */
030public class AssignableTypeFilter extends AbstractTypeHierarchyTraversingFilter {
031
032        private final Class<?> targetType;
033
034
035        /**
036         * Create a new AssignableTypeFilter for the given type.
037         * @param targetType the type to match
038         */
039        public AssignableTypeFilter(Class<?> targetType) {
040                super(true, true);
041                this.targetType = targetType;
042        }
043
044        /**
045         * Return the {@code type} that this instance is using to filter candidates.
046         * @since 5.0
047         */
048        public final Class<?> getTargetType() {
049                return this.targetType;
050        }
051
052        @Override
053        protected boolean matchClassName(String className) {
054                return this.targetType.getName().equals(className);
055        }
056
057        @Override
058        @Nullable
059        protected Boolean matchSuperClass(String superClassName) {
060                return matchTargetType(superClassName);
061        }
062
063        @Override
064        @Nullable
065        protected Boolean matchInterface(String interfaceName) {
066                return matchTargetType(interfaceName);
067        }
068
069        @Nullable
070        protected Boolean matchTargetType(String typeName) {
071                if (this.targetType.getName().equals(typeName)) {
072                        return true;
073                }
074                else if (Object.class.getName().equals(typeName)) {
075                        return false;
076                }
077                else if (typeName.startsWith("java")) {
078                        try {
079                                Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
080                                return this.targetType.isAssignableFrom(clazz);
081                        }
082                        catch (Throwable ex) {
083                                // Class not regularly loadable - can't determine a match that way.
084                        }
085                }
086                return null;
087        }
088
089}