mirror of
https://github.com/apache/struts.git
synced 2026-08-06 15:17:00 +00:00
WW-4744: Remove copied Spring's code (also from PR#117)
This commit is contained in:
+2
-4
@@ -18,8 +18,8 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.annotations.InputConfig;
|
||||
import com.opensymphony.xwork2.util.ReflectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import com.opensymphony.xwork2.util.AnnotationUtils;
|
||||
@@ -211,9 +211,7 @@ public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {
|
||||
InputConfig annotation = AnnotationUtils.findAnnotation(action.getClass().getMethod(method, EMPTY_CLASS_ARRAY), InputConfig.class);
|
||||
if (annotation != null) {
|
||||
if (StringUtils.isNotEmpty(annotation.methodName())) {
|
||||
Method m = ReflectionUtils.findMethod(action.getClass(), annotation.methodName());
|
||||
ReflectionUtils.makeAccessible(m);
|
||||
resultName = (String) ReflectionUtils.invokeMethod(m, action);
|
||||
resultName = (String) MethodUtils.invokeMethod(action, true, annotation.methodName());
|
||||
} else {
|
||||
resultName = annotation.resultName();
|
||||
}
|
||||
|
||||
+4
-7
@@ -20,7 +20,7 @@ import com.opensymphony.xwork2.XWorkException;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.util.AnnotationUtils;
|
||||
import com.opensymphony.xwork2.util.ReflectionUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -123,8 +123,7 @@ public class AnnotationWorkflowInterceptor extends AbstractInterceptor implement
|
||||
}
|
||||
});
|
||||
for (Method m : methods) {
|
||||
ReflectionUtils.makeAccessible(m);
|
||||
final String resultCode = (String) ReflectionUtils.invokeMethod(m, action);
|
||||
final String resultCode = (String) MethodUtils.invokeMethod(action, true, m.getName());
|
||||
if (resultCode != null) {
|
||||
// shortcircuit execution
|
||||
return resultCode;
|
||||
@@ -146,8 +145,7 @@ public class AnnotationWorkflowInterceptor extends AbstractInterceptor implement
|
||||
}
|
||||
});
|
||||
for (Method m : methods) {
|
||||
ReflectionUtils.makeAccessible(m);
|
||||
ReflectionUtils.invokeMethod(m, action);
|
||||
MethodUtils.invokeMethod(action, true, m.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,8 +181,7 @@ public class AnnotationWorkflowInterceptor extends AbstractInterceptor implement
|
||||
});
|
||||
for (Method m : methods) {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(m);
|
||||
ReflectionUtils.invokeMethod(m, action);
|
||||
MethodUtils.invokeMethod(action, true, m.getName());
|
||||
} catch (Exception e) {
|
||||
throw new XWorkException(e);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The Apache Software Foundation.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -17,17 +16,16 @@
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -40,12 +38,6 @@ import java.util.regex.Pattern;
|
||||
* @author Rainer Hermanns
|
||||
* @author Zsolt Szasz, zsolt at lorecraft dot com
|
||||
* @author Dan Oxlade, dan d0t oxlade at gmail d0t c0m
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Mark Fisher
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AnnotationUtils {
|
||||
@@ -53,12 +45,6 @@ public class AnnotationUtils {
|
||||
private static final Pattern SETTER_PATTERN = Pattern.compile("set([A-Z][A-Za-z0-9]*)$");
|
||||
private static final Pattern GETTER_PATTERN = Pattern.compile("(get|is|has)([A-Z][A-Za-z0-9]*)$");
|
||||
|
||||
private static final Map<AnnotationCacheKey, Annotation> findAnnotationCache =
|
||||
new ConcurrentHashMap<AnnotationCacheKey, Annotation>(256);
|
||||
|
||||
private static final Map<Class<?>, Boolean> annotatedInterfaceCache =
|
||||
new ConcurrentHashMap<Class<?>, Boolean>(256);
|
||||
|
||||
/**
|
||||
* Adds all fields with the specified Annotation of class clazz and its superclasses to allFields
|
||||
*
|
||||
@@ -131,136 +117,101 @@ public class AnnotationUtils {
|
||||
* @param annotation the {@link Annotation}s to find
|
||||
* @return A {@link Collection}<{@link AnnotatedElement}> containing all of the
|
||||
* method {@link AnnotatedElement}s matching the specified {@link Annotation}s
|
||||
* @deprecated Will be removed after release of <a href="https://github.com/apache/commons-lang/pull/261">LANG-1317</a>
|
||||
*/
|
||||
public static Collection<Method> getAnnotatedMethods(Class clazz, final Class<? extends Annotation>... annotation) {
|
||||
final Collection<Method> toReturn = new HashSet<>();
|
||||
|
||||
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException {
|
||||
public static Collection<Method> getAnnotatedMethods(Class clazz, Class<? extends Annotation>... annotation) {
|
||||
List<Class<?>> allSuperclasses = ClassUtils.getAllSuperclasses(clazz);
|
||||
allSuperclasses.add(0, clazz);
|
||||
int sci = 0;
|
||||
List<Class<?>> allInterfaces = ClassUtils.getAllInterfaces(clazz);
|
||||
int ifi = 0;
|
||||
final List<Method> annotatedMethods = new ArrayList<>();
|
||||
while (ifi < allInterfaces.size() ||
|
||||
sci < allSuperclasses.size()) {
|
||||
Class<?> acls;
|
||||
if (ifi >= allInterfaces.size()) {
|
||||
acls = allSuperclasses.get(sci++);
|
||||
}
|
||||
else if (sci >= allSuperclasses.size()) {
|
||||
acls = allInterfaces.get(ifi++);
|
||||
}
|
||||
else if (sci <= ifi) {
|
||||
acls = allSuperclasses.get(sci++);
|
||||
}
|
||||
else {
|
||||
acls = allInterfaces.get(ifi++);
|
||||
}
|
||||
final Method[] allMethods = acls.getDeclaredMethods();
|
||||
for (final Method method : allMethods) {
|
||||
if (ArrayUtils.isEmpty(annotation) && ArrayUtils.isNotEmpty(method.getAnnotations())) {
|
||||
toReturn.add(method);
|
||||
return;
|
||||
annotatedMethods.add(method);
|
||||
continue;
|
||||
}
|
||||
for (Class<? extends Annotation> c : annotation) {
|
||||
if (null != findAnnotation(method, c)) {
|
||||
toReturn.add(method);
|
||||
break;
|
||||
if (method.getAnnotation(c) != null) {
|
||||
annotatedMethods.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} from the supplied
|
||||
* {@link Method}, traversing its super methods (i.e., from superclasses and
|
||||
* interfaces) if no annotation can be found on the given method itself.
|
||||
* <p>Annotations on methods are not inherited by default, so we need to handle
|
||||
* this explicitly.
|
||||
*
|
||||
* @param method the method to look for annotations on
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return the annotation found, or {@code null} if none
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
|
||||
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
|
||||
A result = (A) findAnnotationCache.get(cacheKey);
|
||||
if (result == null) {
|
||||
result = getAnnotation(method, annotationType);
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
if (result == null) {
|
||||
result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
|
||||
}
|
||||
while (result == null) {
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz == null || clazz.equals(Object.class)) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
|
||||
result = getAnnotation(equivalentMethod, annotationType);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
// No equivalent method found
|
||||
}
|
||||
if (result == null) {
|
||||
result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
findAnnotationCache.put(cacheKey, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return annotatedMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single {@link Annotation} of {@code annotationType} from the supplied
|
||||
* Method, Constructor or Field. Meta-annotations will be searched if the annotation
|
||||
* is not declared locally on the supplied element.
|
||||
*
|
||||
* @param annotatedElement the Method, Constructor or Field from which to get the annotation
|
||||
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
|
||||
* @return the matching annotation, or {@code null} if none found
|
||||
* <p>BFS to find the annotation object that is present on the given method or any equivalent method in
|
||||
* super classes and interfaces, with the given annotation type. Returns null if the annotation type was not present
|
||||
* on any of them.</p>
|
||||
* @param <A>
|
||||
* the annotation type
|
||||
* @param method
|
||||
* the {@link Method} to query
|
||||
* @param annotationCls
|
||||
* the {@link Annotation} to check if is present on the method
|
||||
* @return an Annotation (possibly null).
|
||||
* @deprecated Will be removed after release of <a href="https://github.com/apache/commons-lang/pull/261">LANG-1317</a>
|
||||
*/
|
||||
public static <T extends Annotation> T getAnnotation(AnnotatedElement annotatedElement, Class<T> annotationType) {
|
||||
try {
|
||||
T ann = annotatedElement.getAnnotation(annotationType);
|
||||
if (ann == null) {
|
||||
for (Annotation metaAnn : annotatedElement.getAnnotations()) {
|
||||
ann = metaAnn.annotationType().getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
public static <A extends Annotation> A findAnnotation(final Method method, final Class<A> annotationCls) {
|
||||
A annotation = method.getAnnotation(annotationCls);
|
||||
|
||||
if(annotation == null) {
|
||||
Class<?> mcls = method.getDeclaringClass();
|
||||
List<Class<?>> allSuperclasses = ClassUtils.getAllSuperclasses(mcls);
|
||||
int sci = 0;
|
||||
List<Class<?>> allInterfaces = ClassUtils.getAllInterfaces(mcls);
|
||||
int ifi = 0;
|
||||
while (ifi < allInterfaces.size() ||
|
||||
sci < allSuperclasses.size()) {
|
||||
Class<?> acls;
|
||||
if(ifi >= allInterfaces.size()) {
|
||||
acls = allSuperclasses.get(sci++);
|
||||
}
|
||||
else if(sci >= allSuperclasses.size()) {
|
||||
acls = allInterfaces.get(ifi++);
|
||||
}
|
||||
else if(ifi <= sci) {
|
||||
acls = allInterfaces.get(ifi++);
|
||||
}
|
||||
else {
|
||||
acls = allSuperclasses.get(sci++);
|
||||
}
|
||||
Method equivalentMethod = null;
|
||||
try {
|
||||
equivalentMethod = acls.getDeclaredMethod(method.getName(), method.getParameterTypes());
|
||||
} catch (NoSuchMethodException e) {
|
||||
// If not found, just keep on breadth first search
|
||||
}
|
||||
if(equivalentMethod != null) {
|
||||
annotation = equivalentMethod.getAnnotation(annotationCls);
|
||||
if(annotation != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ann;
|
||||
} catch (Exception ex) {
|
||||
// Assuming nested Class values not resolvable within annotation attributes...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) {
|
||||
A annotation = null;
|
||||
for (Class<?> iface : ifcs) {
|
||||
if (isInterfaceWithAnnotatedMethods(iface)) {
|
||||
try {
|
||||
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
|
||||
annotation = getAnnotation(equivalentMethod, annotationType);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
// Skip this interface - it doesn't have the method...
|
||||
}
|
||||
if (annotation != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
|
||||
private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
|
||||
Boolean flag = annotatedInterfaceCache.get(iface);
|
||||
if (flag != null) {
|
||||
return flag;
|
||||
}
|
||||
boolean found = false;
|
||||
for (Method ifcMethod : iface.getMethods()) {
|
||||
try {
|
||||
if (ifcMethod.getAnnotations().length > 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Assuming nested Class values not resolvable within annotation attributes...
|
||||
}
|
||||
}
|
||||
annotatedInterfaceCache.put(iface, found);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property name for a method.
|
||||
* This method is independent from property fields.
|
||||
@@ -295,61 +246,20 @@ public class AnnotationUtils {
|
||||
* @return The annotation or null.
|
||||
*/
|
||||
public static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotationClass) {
|
||||
AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationClass);
|
||||
T ann = (T) findAnnotationCache.get(cacheKey);
|
||||
if (ann == null) {
|
||||
T ann = clazz.getAnnotation(annotationClass);
|
||||
while (ann == null && clazz != null) {
|
||||
ann = clazz.getAnnotation(annotationClass);
|
||||
while (ann == null && clazz != null) {
|
||||
ann = clazz.getAnnotation(annotationClass);
|
||||
if (ann == null) {
|
||||
ann = clazz.getPackage().getAnnotation(annotationClass);
|
||||
}
|
||||
if (ann == null) {
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz != null) {
|
||||
ann = clazz.getAnnotation(annotationClass);
|
||||
}
|
||||
}
|
||||
if (ann == null) {
|
||||
ann = clazz.getPackage().getAnnotation(annotationClass);
|
||||
}
|
||||
if (ann != null) {
|
||||
findAnnotationCache.put(cacheKey, ann);
|
||||
if (ann == null) {
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz != null) {
|
||||
ann = clazz.getAnnotation(annotationClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ann;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cache key for the AnnotatedElement cache.
|
||||
*/
|
||||
private static class AnnotationCacheKey {
|
||||
|
||||
private final AnnotatedElement element;
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
public AnnotationCacheKey(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
this.element = element;
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AnnotationCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
AnnotationCacheKey otherKey = (AnnotationCacheKey) other;
|
||||
return (this.element.equals(otherKey.element) &&
|
||||
this.annotationType.equals(otherKey.annotationType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.element.hashCode() * 29 + this.annotationType.hashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 The Apache Software Foundation.
|
||||
* Copyright 2002-2015 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
|
||||
*
|
||||
* http://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 com.opensymphony.xwork2.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Simple utility class for working with the reflection API and handling
|
||||
* reflection exceptions.
|
||||
*
|
||||
* <p>Only intended for internal use.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Rod Johnson
|
||||
* @author Costin Leau
|
||||
* @author Sam Brannen
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public abstract class ReflectionUtils {
|
||||
|
||||
/**
|
||||
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast iteration.
|
||||
*/
|
||||
private static final Map<Class<?>, Method[]> declaredMethodsCache =
|
||||
new ConcurrentHashMap<Class<?>, Method[]>(256);
|
||||
|
||||
/**
|
||||
* Perform the given callback operation on all matching methods of the given
|
||||
* class and superclasses.
|
||||
* <p>The same named method occurring on subclass and superclass will appear
|
||||
* twice, unless excluded by a {@link MethodFilter}.
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @see #doWithMethods(Class, MethodCallback, MethodFilter)
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
|
||||
doWithMethods(clazz, mc, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given callback operation on all matching methods of the given
|
||||
* class and superclasses (or given interface and super-interfaces).
|
||||
* <p>The same named method occurring on subclass and superclass will appear
|
||||
* twice, unless excluded by the specified {@link MethodFilter}.
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @param mf the filter that determines the methods to apply the callback to
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
Method[] methods = getDeclaredMethods(clazz);
|
||||
for (Method method : methods) {
|
||||
if (mf != null && !mf.matches(method)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
mc.doWith(method);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
|
||||
}
|
||||
}
|
||||
if (clazz.getSuperclass() != null) {
|
||||
doWithMethods(clazz.getSuperclass(), mc, mf);
|
||||
}
|
||||
else if (clazz.isInterface()) {
|
||||
for (Class<?> superIfc : clazz.getInterfaces()) {
|
||||
doWithMethods(superIfc, mc, mf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the given method accessible, explicitly setting it accessible if
|
||||
* necessary. The {@code setAccessible(true)} method is only called
|
||||
* when actually necessary, to avoid unnecessary conflicts with a JVM
|
||||
* SecurityManager (if active).
|
||||
* @param method the method to make accessible
|
||||
* @see java.lang.reflect.Method#setAccessible
|
||||
*/
|
||||
public static void makeAccessible(Method method) {
|
||||
if ((!Modifier.isPublic(method.getModifiers()) ||
|
||||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
|
||||
method.setAccessible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find a {@link Method} on the supplied class with the supplied name
|
||||
* and no parameters. Searches all superclasses up to {@code Object}.
|
||||
* <p>Returns {@code null} if no {@link Method} can be found.
|
||||
* @param clazz the class to introspect
|
||||
* @param name the name of the method
|
||||
* @return the Method object, or {@code null} if none found
|
||||
*/
|
||||
public static Method findMethod(Class<?> clazz, String name) {
|
||||
return findMethod(clazz, name, new Class<?>[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find a {@link Method} on the supplied class with the supplied name
|
||||
* and parameter types. Searches all superclasses up to {@code Object}.
|
||||
* <p>Returns {@code null} if no {@link Method} can be found.
|
||||
* @param clazz the class to introspect
|
||||
* @param name the name of the method
|
||||
* @param paramTypes the parameter types of the method
|
||||
* (may be {@code null} to indicate any signature)
|
||||
* @return the Method object, or {@code null} if none found
|
||||
*/
|
||||
public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
|
||||
Class<?> searchType = clazz;
|
||||
while (searchType != null) {
|
||||
Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));
|
||||
for (Method method : methods) {
|
||||
if (name.equals(method.getName()) &&
|
||||
(paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
searchType = searchType.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the specified {@link Method} against the supplied target object with no arguments.
|
||||
* The target object can be {@code null} when invoking a static {@link Method}.
|
||||
* <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}.
|
||||
* @param method the method to invoke
|
||||
* @param target the target object to invoke the method on
|
||||
* @return the invocation result, if any
|
||||
* @see #invokeMethod(java.lang.reflect.Method, Object, Object[])
|
||||
*/
|
||||
public static Object invokeMethod(Method method, Object target) {
|
||||
return invokeMethod(method, target, new Object[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the specified {@link Method} against the supplied target object with the
|
||||
* supplied arguments. The target object can be {@code null} when invoking a
|
||||
* static {@link Method}.
|
||||
* <p>Thrown exceptions are handled via a call to {@link #handleReflectionException}.
|
||||
* @param method the method to invoke
|
||||
* @param target the target object to invoke the method on
|
||||
* @param args the invocation arguments (may be {@code null})
|
||||
* @return the invocation result, if any
|
||||
*/
|
||||
public static Object invokeMethod(Method method, Object target, Object... args) {
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleReflectionException(ex);
|
||||
}
|
||||
throw new IllegalStateException("Should never get here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given reflection exception. Should only be called if no
|
||||
* checked exception is expected to be thrown by the target method.
|
||||
* <p>Throws the underlying RuntimeException or Error in case of an
|
||||
* InvocationTargetException with such a root cause. Throws an
|
||||
* IllegalStateException with an appropriate message else.
|
||||
* @param ex the reflection exception to handle
|
||||
*/
|
||||
public static void handleReflectionException(Exception ex) {
|
||||
if (ex instanceof NoSuchMethodException) {
|
||||
throw new IllegalStateException("Method not found: " + ex.getMessage());
|
||||
}
|
||||
if (ex instanceof IllegalAccessException) {
|
||||
throw new IllegalStateException("Could not access method: " + ex.getMessage());
|
||||
}
|
||||
if (ex instanceof InvocationTargetException) {
|
||||
handleInvocationTargetException((InvocationTargetException) ex);
|
||||
}
|
||||
if (ex instanceof RuntimeException) {
|
||||
throw (RuntimeException) ex;
|
||||
}
|
||||
throw new UndeclaredThrowableException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given invocation target exception. Should only be called if no
|
||||
* checked exception is expected to be thrown by the target method.
|
||||
* <p>Throws the underlying RuntimeException or Error in case of such a root
|
||||
* cause. Throws an IllegalStateException else.
|
||||
* @param ex the invocation target exception to handle
|
||||
*/
|
||||
public static void handleInvocationTargetException(InvocationTargetException ex) {
|
||||
rethrowRuntimeException(ex.getTargetException());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rethrow the given {@link Throwable exception}, which is presumably the
|
||||
* <em>target exception</em> of an {@link InvocationTargetException}. Should
|
||||
* only be called if no checked exception is expected to be thrown by the
|
||||
* target method.
|
||||
* <p>Rethrows the underlying exception cast to an {@link RuntimeException} or
|
||||
* {@link Error} if appropriate; otherwise, throws an
|
||||
* {@link IllegalStateException}.
|
||||
* @param ex the exception to rethrow
|
||||
* @throws RuntimeException the rethrown exception
|
||||
*/
|
||||
public static void rethrowRuntimeException(Throwable ex) {
|
||||
if (ex instanceof RuntimeException) {
|
||||
throw (RuntimeException) ex;
|
||||
}
|
||||
if (ex instanceof Error) {
|
||||
throw (Error) ex;
|
||||
}
|
||||
throw new UndeclaredThrowableException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* This variant retrieves {@link Class#getDeclaredMethods()} from a local cache
|
||||
* in order to avoid the JVM's SecurityManager check and defensive array copying.
|
||||
*/
|
||||
private static Method[] getDeclaredMethods(Class<?> clazz) {
|
||||
Method[] result = declaredMethodsCache.get(clazz);
|
||||
if (result == null) {
|
||||
result = clazz.getDeclaredMethods();
|
||||
declaredMethodsCache.put(clazz, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action to take on each method.
|
||||
*/
|
||||
public interface MethodCallback {
|
||||
|
||||
/**
|
||||
* Perform an operation using the given method.
|
||||
* @param method the method to operate on
|
||||
*/
|
||||
void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback optionally used to filter methods to be operated on by a method callback.
|
||||
*/
|
||||
public interface MethodFilter {
|
||||
|
||||
/**
|
||||
* Determine whether the given method matches.
|
||||
* @param method the method to check
|
||||
*/
|
||||
boolean matches(Method method);
|
||||
}
|
||||
}
|
||||
-5
@@ -23,17 +23,12 @@ package org.apache.struts2.interceptor.validation;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.AnnotationUtils;
|
||||
import com.opensymphony.xwork2.validator.ValidationInterceptor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Extends the xwork validation interceptor to also check for a @SkipValidation
|
||||
|
||||
@@ -3,13 +3,13 @@ package com.opensymphony.xwork2.util;
|
||||
import com.opensymphony.xwork2.util.annotation.Dummy2Class;
|
||||
import com.opensymphony.xwork2.util.annotation.DummyClass;
|
||||
import com.opensymphony.xwork2.util.annotation.DummyClassExt;
|
||||
import com.opensymphony.xwork2.util.annotation.DummyInterface;
|
||||
import com.opensymphony.xwork2.util.annotation.MyAnnotation;
|
||||
import com.opensymphony.xwork2.util.annotation.MyAnnotation2;
|
||||
import com.opensymphony.xwork2.util.annotation.MyAnnotationI;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -18,15 +18,6 @@ import java.util.Collection;
|
||||
*/
|
||||
public class AnnotationUtilsTest extends TestCase {
|
||||
|
||||
public void testGetAnnotationMeta() throws Exception {
|
||||
assertNotNull(AnnotationUtils.getAnnotation(DummyClass.class.getMethod("methodWithAnnotation"), Retention.class));
|
||||
}
|
||||
|
||||
public void testGetAnnotation() throws Exception {
|
||||
assertNull(AnnotationUtils.getAnnotation(DummyClass.class.getMethod("methodWithAnnotation"), Deprecated.class));
|
||||
assertNotNull(AnnotationUtils.getAnnotation(DummyClass.class.getMethod("methodWithAnnotation"), MyAnnotation.class));
|
||||
}
|
||||
|
||||
public void testFindAnnotationFromSuperclass() throws Exception {
|
||||
assertNotNull(AnnotationUtils.findAnnotation(DummyClassExt.class.getMethod("methodWithAnnotation"), MyAnnotation.class));
|
||||
}
|
||||
@@ -43,15 +34,16 @@ public class AnnotationUtilsTest extends TestCase {
|
||||
public void testGetAnnotatedMethodsIncludingSuperclassAndInterface() throws Exception {
|
||||
|
||||
Collection<? extends AnnotatedElement> ans = AnnotationUtils.getAnnotatedMethods(DummyClassExt.class, Deprecated.class, MyAnnotation.class, MyAnnotation2.class, MyAnnotationI.class);
|
||||
assertEquals(5, ans.size());
|
||||
assertEquals(4, ans.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testGetAnnotatedMethodsWithoutAnnotationArgs() throws Exception {
|
||||
Collection<? extends AnnotatedElement> ans = AnnotationUtils.getAnnotatedMethods(DummyClass.class);
|
||||
assertTrue(ans.size() == 2);
|
||||
assertEquals(3, ans.size());
|
||||
assertTrue(ans.contains(DummyClass.class.getMethod("methodWithAnnotation")));
|
||||
assertTrue(ans.contains(DummyClass.class.getDeclaredMethod("privateMethodWithAnnotation")));
|
||||
assertTrue(ans.contains(DummyInterface.class.getDeclaredMethod("interfaceMethodWithAnnotation")));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -69,7 +61,7 @@ public class AnnotationUtilsTest extends TestCase {
|
||||
assertEquals(2, ans.size());
|
||||
|
||||
ans = AnnotationUtils.getAnnotatedMethods(DummyClassExt.class, MyAnnotation.class, MyAnnotation2.class);
|
||||
assertEquals(4, ans.size());
|
||||
assertEquals(3, ans.size());
|
||||
}
|
||||
|
||||
public void testFindAnnotationOnClass() {
|
||||
|
||||
-1
@@ -39,7 +39,6 @@ import org.apache.struts2.interceptor.validation.SkipValidation;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validator;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user