From ad6cda80bed6ca080b18f58b45d5bdcec12d5cac Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 27 Aug 2017 03:32:40 +0900 Subject: [PATCH] When scanning super interfaces in `OgnlRuntime#getMethods(Class, boolean)`, only default methods should be collected instead of all declared methods. Also, super interfaces should be searched recursively so that it can handle deeper interface hierarchy. --- src/java/ognl/OgnlRuntime.java | 74 ++++++++++++++++++------------- src/test/java/ognl/Java8Test.java | 6 ++- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/java/ognl/OgnlRuntime.java b/src/java/ognl/OgnlRuntime.java index 727b1d4a..a2d9c7bf 100644 --- a/src/java/ognl/OgnlRuntime.java +++ b/src/java/ognl/OgnlRuntime.java @@ -1768,43 +1768,57 @@ public static Map getMethods(Class targetClass, boolean staticMethods) if ((result = (Map) cache.get(targetClass)) == null) { result = new HashMap(23); + collectMethods(targetClass, result, staticMethods); + cache.put(targetClass, result); + } + } + } + return result; + } - List toExamined = new LinkedList(); - for (Class c = targetClass; c != null; c = c.getSuperclass()) - { - toExamined.add(c); - - // Including interfaces is needed as from Java 8 intefaces can implement default methods - toExamined.addAll(Arrays.asList(c.getInterfaces())); - } + private static void collectMethods(Class c, Map result, boolean staticMethods) { + final Method[] ma = c.getDeclaredMethods(); + for (int i = 0, icount = ma.length; i < icount; i++) + { + if (c.isInterface()) + { + if (isDefaultMethod(ma[i])) + addMethodToResult(result, ma[i]); + continue; + } - for (Class c : toExamined) - { - Method[] ma = c.getDeclaredMethods(); + // skip over synthetic methods + if (!isMethodCallable(ma[i])) + continue; - for (int i = 0, icount = ma.length; i < icount; i++) - { - // skip over synthetic methods + if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods) + addMethodToResult(result, ma[i]); + } - if (!isMethodCallable(ma[i])) - continue; + final Class superclass = c.getSuperclass(); + if (superclass != null) + collectMethods(superclass, result, staticMethods); - if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods) - { - List ml = (List) result.get(ma[i].getName()); + for (final Class iface : c.getInterfaces()) + collectMethods(iface, result, staticMethods); + } - if (ml == null) - result.put(ma[i].getName(), ml = new ArrayList()); + private static void addMethodToResult(Map result, Method method) + { + List ml = (List) result.get(method.getName()); + if (ml == null) + result.put(method.getName(), ml = new ArrayList()); + ml.add(method); + } - ml.add(ma[i]); - } - } - } - cache.put(targetClass, result); - } - } - } - return result; + /** + * Backport of java.lang.reflect.Method#isDefault() + */ + private static boolean isDefaultMethod(Method method) + { + return ((method.getModifiers() + & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC) + && method.getDeclaringClass().isInterface(); } public static Map getAllMethods(Class targetClass, boolean staticMethods) diff --git a/src/test/java/ognl/Java8Test.java b/src/test/java/ognl/Java8Test.java index d746f1e8..ea36370e 100644 --- a/src/test/java/ognl/Java8Test.java +++ b/src/test/java/ognl/Java8Test.java @@ -39,7 +39,7 @@ class SubClassWithDefaults extends ClassWithDefaults { } -class ClassWithDefaults /* implements InterfaceWithDefaults */ { +class ClassWithDefaults /* implements SubInterfaceWithDefaults */ { } @@ -50,4 +50,6 @@ interface InterfaceWithDefaults { default public void defaultMethod() { } default public String getName() { return "name"; } } - */ +interface SubInterfaceWithDefaults extends InterfaceWithDefaults { +} + */ \ No newline at end of file