All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.core.MethodIntrospector Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-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
 *
 *      https://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.core;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
 * Defines the algorithm for searching for metadata-associated methods exhaustively
 * including interfaces and parent classes while also dealing with parameterized methods
 * as well as common scenarios encountered with interface and class-based proxies.
 *
 * 

Typically, but not necessarily, used for finding annotated handler methods. * * @author Juergen Hoeller * @author Rossen Stoyanchev * @since 4.2.3 */ public abstract class MethodIntrospector { /** * Select methods on the given target type based on the lookup of associated metadata. *

Callers define methods of interest through the {@link MetadataLookup} parameter, * allowing to collect the associated metadata into the result map. * @param targetType the target type to search methods on * @param metadataLookup a {@link MetadataLookup} callback to inspect methods of interest, * returning non-null metadata to be associated with a given method if there is a match, * or {@code null} for no match * @return the selected methods associated with their metadata (in the order of retrieval), * or an empty map in case of no match */ public static Map selectMethods(Class targetType, final MetadataLookup metadataLookup) { final Map methodMap = new LinkedHashMap(); Set> handlerTypes = new LinkedHashSet>(); Class specificHandlerType = null; if (!Proxy.isProxyClass(targetType)) { handlerTypes.add(targetType); specificHandlerType = targetType; } handlerTypes.addAll(Arrays.asList(targetType.getInterfaces())); for (Class currentHandlerType : handlerTypes) { final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType); ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) { Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); T result = metadataLookup.inspect(specificMethod); if (result != null) { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) { methodMap.put(specificMethod, result); } } } }, ReflectionUtils.USER_DECLARED_METHODS); } return methodMap; } /** * Select methods on the given target type based on a filter. *

Callers define methods of interest through the {@code MethodFilter} parameter. * @param targetType the target type to search methods on * @param methodFilter a {@code MethodFilter} to help * recognize handler methods of interest * @return the selected methods, or an empty set in case of no match */ public static Set selectMethods(Class targetType, final ReflectionUtils.MethodFilter methodFilter) { return selectMethods(targetType, new MetadataLookup() { @Override public Boolean inspect(Method method) { return (methodFilter.matches(method) ? Boolean.TRUE : null); } }).keySet(); } /** * Select an invocable method on the target type: either the given method itself * if actually exposed on the target type, or otherwise a corresponding method * on one of the target type's interfaces or on the target type itself. *

Matches on user-declared interfaces will be preferred since they are likely * to contain relevant metadata that corresponds to the method on the target class. * @param method the method to check * @param targetType the target type to search methods on * (typically an interface-based JDK proxy) * @return a corresponding invocable method on the target type * @throws IllegalStateException if the given method is not invocable on the given * target type (typically due to a proxy mismatch) */ public static Method selectInvocableMethod(Method method, Class targetType) { if (method.getDeclaringClass().isAssignableFrom(targetType)) { return method; } try { String methodName = method.getName(); Class[] parameterTypes = method.getParameterTypes(); for (Class ifc : targetType.getInterfaces()) { try { return ifc.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException ex) { // Alright, not on this interface then... } } // A final desperate attempt on the proxy class itself... return targetType.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException ex) { throw new IllegalStateException(String.format( "Need to invoke method '%s' declared on target class '%s', " + "but not found in any interface(s) of the exposed proxy type. " + "Either pull the method up to an interface or switch to CGLIB " + "proxies by enforcing proxy-target-class mode in your configuration.", method.getName(), method.getDeclaringClass().getSimpleName())); } } /** * A callback interface for metadata lookup on a given method. * @param the type of metadata returned */ public interface MetadataLookup { /** * Perform a lookup on the given method and return associated metadata, if any. * @param method the method to inspect * @return non-null metadata to be associated with a method if there is a match, * or {@code null} for no match */ T inspect(Method method); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy