Repository: incubator-juneau Updated Branches: refs/heads/master d94d89db6 -> 3551f4c9c
Fix issue where annotations were not being found on parent classes. Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/3551f4c9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/3551f4c9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/3551f4c9 Branch: refs/heads/master Commit: 3551f4c9ca19a72186385c55f9e93f79148a18e8 Parents: d94d89d Author: JamesBognar <[email protected]> Authored: Fri Jun 2 17:16:57 2017 -0400 Committer: JamesBognar <[email protected]> Committed: Fri Jun 2 17:16:57 2017 -0400 ---------------------------------------------------------------------- .../org/apache/juneau/utils/ClassUtilsTest.java | 50 ++++++++++++++++ .../main/java/org/apache/juneau/BeanMeta.java | 12 ++-- .../org/apache/juneau/internal/ClassUtils.java | 61 +++++++++++++------- .../main/javadoc/resources/icons/LICENSE.txt | 14 +++++ .../juneau/rest/test/RequestBeanProxyTest.java | 45 ++++++++++++--- 5 files changed, 147 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3551f4c9/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java b/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java index 688c2bc..8b5ad42 100755 --- a/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java +++ b/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java @@ -12,9 +12,14 @@ // *************************************************************************************************************************** package org.apache.juneau.utils; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; import static org.apache.juneau.internal.ClassUtils.*; import static org.junit.Assert.*; +import java.lang.annotation.*; + +import org.apache.juneau.internal.*; import org.junit.*; @SuppressWarnings("javadoc") @@ -148,4 +153,49 @@ public class ClassUtilsTest { public void m5(int f1, CharSequence f2) {} } + + + //==================================================================================================== + // getMethodAnnotation + //==================================================================================================== + @Test + public void getMethodAnnotation() throws Exception { + assertEquals("a1", ClassUtils.getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a1")).value()); + assertEquals("a2b", ClassUtils.getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a2")).value()); + assertEquals("a3", ClassUtils.getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a3", CharSequence.class)).value()); + assertEquals("a4", ClassUtils.getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a4")).value()); + } + + public static interface CI1 { + @TestAnnotation("a1") + void a1(); + @TestAnnotation("a2a") + void a2(); + @TestAnnotation("a3") + void a3(CharSequence foo); + + void a4(); + } + + public static class CI2 implements CI1 { + public void a1() {} + @TestAnnotation("a2b") + public void a2() {} + public void a3(CharSequence s) {} + public void a4() {} + } + + public static class CI3 extends CI2 { + @Override + public void a1() {} + @Override public void a2() {} + @TestAnnotation("a4") + public void a4() {} + } + + @Target(METHOD) + @Retention(RUNTIME) + public @interface TestAnnotation { + String value() default ""; + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3551f4c9/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java index cb51ed5..be80772 100644 --- a/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java +++ b/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java @@ -547,17 +547,21 @@ public class BeanMeta<T> { int mod = m.getModifiers(); if (Modifier.isStatic(mod)) continue; - if (m.isAnnotationPresent(BeanIgnore.class)) - continue; if (m.isBridge()) // This eliminates methods with covariant return types from parent classes on child classes. continue; - if (! (v.isVisible(m) || m.isAnnotationPresent(BeanProperty.class))) + + BeanIgnore bi = getMethodAnnotation(BeanIgnore.class, c, m); + if (bi != null) continue; + + BeanProperty bp = getMethodAnnotation(BeanProperty.class, c, m); + if (! (v.isVisible(m) || bp != null)) + continue; + String n = m.getName(); Class<?>[] pt = m.getParameterTypes(); Class<?> rt = m.getReturnType(); boolean isGetter = false, isSetter = false; - BeanProperty bp = getMethodAnnotation(BeanProperty.class, m); String bpName = bpName(bp); if (pt.length == 0) { if (n.startsWith("get") && (! rt.equals(Void.TYPE))) { http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3551f4c9/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java index d176b92..3b31bfc 100644 --- a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java +++ b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java @@ -336,36 +336,53 @@ public final class ClassUtils { * Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation * defined on parent classes and interfaces. * <p> - * Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child - * methods. - * This utility method gets around that limitation by searching the class hierarchy for the "same" method. + * Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods. + * This utility method gets around that limitation by searching the class hierarchy for the "same" method + * (i.e. the same name and arguments). * * @param a The annotation to search for. * @param m The method to search. * @return The annotation, or <jk>null</jk> if it wasn't found. */ public static <T extends Annotation> T getMethodAnnotation(Class<T> a, Method m) { - T t = m.getAnnotation(a); - if (t != null) - return t; - Class<?> pc = m.getDeclaringClass().getSuperclass(); - if (pc != null) { - for (Method m2 : pc.getDeclaredMethods()) { - if (isSameMethod(m, m2)) { - t = getMethodAnnotation(a, m2); - if (t != null) - return t; - } + return getMethodAnnotation(a, m.getDeclaringClass(), m); + } + + /** + * Returns the specified annotation on the specified method. + * <p> + * Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation defined + * on parent classes and interfaces. + * <p> + * Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods. + * This utility method gets around that limitation by searching the class hierarchy for the "same" method + * (i.e. the same name and arguments). + * + * @param a The annotation to search for. + * @param c The child class to start searching from. + * Note that it can be a descendant class of the actual declaring class of the method passed in. + * This allows you to find annotations on methods overridden by the method passed in. + * @param method The method to search. + * @return The annotation, or <jk>null</jk> if it wasn't found. + */ + public static <T extends Annotation> T getMethodAnnotation(Class<T> a, Class<?> c, Method method) { + for (Method m : c.getDeclaredMethods()) { + if (isSameMethod(method, m)) { + T t = m.getAnnotation(a); + if (t != null) + return t; } } - for (Class<?> ic : m.getDeclaringClass().getInterfaces()) { - for (Method m2 : ic.getDeclaredMethods()) { - if (isSameMethod(m, m2)) { - t = getMethodAnnotation(a, m2); - if (t != null) - return t; - } - } + Class<?> pc = c.getSuperclass(); + if (pc != null) { + T t = getMethodAnnotation(a, pc, method); + if (t != null) + return t; + } + for (Class<?> ic : c.getInterfaces()) { + T t = getMethodAnnotation(a, ic, method); + if (t != null) + return t; } return null; } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3551f4c9/juneau-core/src/main/javadoc/resources/icons/LICENSE.txt ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/javadoc/resources/icons/LICENSE.txt b/juneau-core/src/main/javadoc/resources/icons/LICENSE.txt new file mode 100644 index 0000000..bba1297 --- /dev/null +++ b/juneau-core/src/main/javadoc/resources/icons/LICENSE.txt @@ -0,0 +1,14 @@ +*************************************************************************************************************************** +* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +* distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +* to you 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. * +*************************************************************************************************************************** + +This license covers the png files located in this directory. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3551f4c9/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java index 93403fb..5f587b5 100644 --- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java +++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java @@ -176,45 +176,72 @@ public class RequestBeanProxyTest extends RestTestcase { String queryCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryCollections rb); } - public static class RequestBean_QuerySimpleVals { + public static interface RequestBean_QuerySimpleVals_Interface { @Query + String getA(); + + @Query("b") + String getX1(); + + @Query(name="c") + String getX2(); + + @Query + @BeanProperty("d") + String getX3(); + + @Query("e") + String getX4(); + + @Query("f") + String getX5(); + + @Query("g") + String getX6(); + + @Query("h") + String getX7(); + } + + public static class RequestBean_QuerySimpleVals implements RequestBean_QuerySimpleVals_Interface { + + @Override public String getA() { return "a1"; } - @Query("b") + @Override public String getX1() { return "b1"; } - @Query(name="c") + @Override public String getX2() { return "c1"; } - @Query - @BeanProperty("d") + @Override public String getX3() { return "d1"; } - @Query("e") + @Override public String getX4() { return ""; } - @Query("f") + @Override public String getX5() { return null; } - @Query("g") + @Override public String getX6() { return "true"; } - @Query("h") + @Override public String getX7() { return "123"; }
