struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lukaszlen...@apache.org
Subject [1/3] struts git commit: [WW-4694] annotation processing improved in order to navigate around proxies, superclasses and interfaces
Date Mon, 13 Feb 2017 10:55:19 GMT
Repository: struts
Updated Branches:
  refs/heads/master 4b96958be -> 534dfc6bd


[WW-4694] annotation processing improved in order to navigate around
proxies, superclasses and interfaces

Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/c84b7967
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/c84b7967
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/c84b7967

Branch: refs/heads/master
Commit: c84b7967e9eb2f6307466b1644977423831d2ef1
Parents: 0023d96
Author: Yasser Zamani <yasser.zamani@live.com>
Authored: Sun Feb 5 17:54:28 2017 +0330
Committer: Yasser Zamani <yasser.zamani@live.com>
Committed: Sun Feb 5 17:54:28 2017 +0330

----------------------------------------------------------------------
 .../xwork2/util/AnnotationUtils.java            | 111 ++++++++++++++++---
 .../xwork2/util/AnnotationUtilsTest.java        |  35 ++++--
 .../xwork2/util/annotation/DummyClass.java      |   5 +-
 .../xwork2/util/annotation/DummyClassExt.java   |   5 +-
 .../xwork2/util/annotation/DummyInterface.java  |   7 ++
 .../xwork2/util/annotation/MyAnnotationI.java   |   8 ++
 6 files changed, 145 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/main/java/com/opensymphony/xwork2/util/AnnotationUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/AnnotationUtils.java b/core/src/main/java/com/opensymphony/xwork2/util/AnnotationUtils.java
index ef0ee53..1c37918 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/AnnotationUtils.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/AnnotationUtils.java
@@ -122,7 +122,14 @@ public class AnnotationUtils {
         Collection<Method> toReturn = new HashSet<>();
 
         for (Method m : clazz.getMethods()) {
-            if (ArrayUtils.isNotEmpty(annotation) && isAnnotatedBy(m, annotation))
{
+        	boolean found = false;
+    		for( Class<? extends Annotation> c : annotation ){
+    			if( null != findAnnotation(m, c) ){
+    				found =  true;
+    				break;
+    			}
+    		}
+            if (found) {
                 toReturn.add(m);
             } else if (ArrayUtils.isEmpty(annotation) && ArrayUtils.isNotEmpty(m.getAnnotations()))
{
                 toReturn.add(m);
@@ -133,22 +140,100 @@ public class AnnotationUtils {
 	}
 
 	/**
-	 * Varargs version of <code>AnnotatedElement.isAnnotationPresent()</code>
-     * @param annotatedElement element to check
-     * @param annotation the {@link Annotation}s to find
-     * @return true is element is annotated by one of the annotation
-	 * @see AnnotatedElement
+	 * 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 boolean isAnnotatedBy(AnnotatedElement annotatedElement, Class<? extends
Annotation>... annotation) {
-        if (ArrayUtils.isEmpty(annotation)) {
-            return false;
-        }
+	public static <A extends Annotation> A findAnnotation(Method method, Class<A>
annotationType) {
+		A 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());
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * 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
+	 */
+	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) {
+						break;
+					}
+				}
+			}
+			return ann;
+		}
+		catch (Exception ex) {
+			// Assuming nested Class values not resolvable within annotation attributes...
+			return null;
+		}
+	}
 
-		for( Class<? extends Annotation> c : annotation ){
-			if( annotatedElement.isAnnotationPresent(c) ) return true;
+	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;
+	}
 
-		return false;
+	private static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
+		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...
+			}
+		}
+		return found;
 	}
 
     /**

http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java b/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
index e59abe6..8ad4f35 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
@@ -5,8 +5,11 @@ import com.opensymphony.xwork2.util.annotation.DummyClass;
 import com.opensymphony.xwork2.util.annotation.DummyClassExt;
 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;
 
@@ -15,22 +18,32 @@ import java.util.Collection;
  */
 public class AnnotationUtilsTest extends TestCase {
 
-    @SuppressWarnings("unchecked")
-    public void testIsAnnotatedByWithoutAnnotationArgsReturnsFalse() throws Exception {
-        assertFalse(AnnotationUtils.isAnnotatedBy(DummyClass.class));
-        assertFalse(AnnotationUtils.isAnnotatedBy(DummyClass.class.getMethod("methodWithAnnotation")));
+    public void testGetAnnotationMeta() throws Exception {
+        assertNotNull(AnnotationUtils.getAnnotation(DummyClass.class.getMethod("methodWithAnnotation"),
Retention.class));
     }
 
-    @SuppressWarnings("unchecked")
-    public void testIsAnnotatedByWithSingleAnnotationArgMatchingReturnsTrue() throws Exception
{
-        assertTrue(AnnotationUtils.isAnnotatedBy(DummyClass.class.getMethod("methodWithAnnotation"),
MyAnnotation.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));
+    }
+
+    public void testFindAnnotationFromInterface() throws Exception {
+        assertNotNull(AnnotationUtils.findAnnotation(DummyClass.class.getMethod("interfaceMethodWithAnnotation"),
MyAnnotationI.class));
+    }
+
+    public void testFindAnnotation() throws Exception {
+        assertNotNull(AnnotationUtils.findAnnotation(DummyClassExt.class.getMethod("anotherAnnotatedMethod"),
MyAnnotation2.class));
     }
 
     @SuppressWarnings("unchecked")
-    public void testIsAnnotatedByWithMultiAnnotationArgMatchingReturnsTrue() throws Exception
{
-        assertFalse(AnnotationUtils.isAnnotatedBy(DummyClass.class.getMethod("methodWithAnnotation"),
Deprecated.class));
-        assertTrue(AnnotationUtils.isAnnotatedBy(DummyClass.class.getMethod("methodWithAnnotation"),
MyAnnotation.class, Deprecated.class));
-        assertTrue(AnnotationUtils.isAnnotatedBy(DummyClass.class.getMethod("methodWithAnnotation"),
Deprecated.class, MyAnnotation.class));
+    public void testGetAnnotatedMethodsIncludingSuperclassAndInterface() throws Exception
{
+
+        Collection<? extends AnnotatedElement> ans = AnnotationUtils.getAnnotatedMethods(DummyClassExt.class,
Deprecated.class, MyAnnotation.class, MyAnnotation2.class, MyAnnotationI.class);
+        assertEquals(3, ans.size());
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClass.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClass.java b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClass.java
index 22d6e07..da2f80e 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClass.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClass.java
@@ -1,7 +1,7 @@
 package com.opensymphony.xwork2.util.annotation;
 
 @MyAnnotation("class-test")
-public class DummyClass {
+public class DummyClass implements DummyInterface {
 
     public DummyClass() {
     }
@@ -10,4 +10,7 @@ public class DummyClass {
     public void methodWithAnnotation() {
     }
 
+	@Override
+	public void interfaceMethodWithAnnotation() {
+	}
 }

http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClassExt.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClassExt.java
b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClassExt.java
index cfeebdf..7c024f6 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClassExt.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyClassExt.java
@@ -5,5 +5,8 @@ public final class DummyClassExt extends DummyClass {
     @MyAnnotation2
     public void anotherAnnotatedMethod() {
     }
-
+    
+	@Override
+	public void methodWithAnnotation() {
+	}
 }

http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyInterface.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyInterface.java
b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyInterface.java
new file mode 100644
index 0000000..6faa3e4
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/annotation/DummyInterface.java
@@ -0,0 +1,7 @@
+package com.opensymphony.xwork2.util.annotation;
+
+public interface DummyInterface {
+	
+	@MyAnnotationI
+	public void interfaceMethodWithAnnotation();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/struts/blob/c84b7967/core/src/test/java/com/opensymphony/xwork2/util/annotation/MyAnnotationI.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/annotation/MyAnnotationI.java
b/core/src/test/java/com/opensymphony/xwork2/util/annotation/MyAnnotationI.java
new file mode 100644
index 0000000..ea866b9
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/annotation/MyAnnotationI.java
@@ -0,0 +1,8 @@
+package com.opensymphony.xwork2.util.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MyAnnotationI {
+}


Mime
View raw message