From 762994ceed266e8f8c7c9ca5db61d91975db1c81 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Wed, 15 Nov 2017 23:51:48 +0900 Subject: [PATCH] Backporting #40 to ognl-3-1-x branch. 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 | 7 ++- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/java/ognl/OgnlRuntime.java b/src/java/ognl/OgnlRuntime.java index 3424d7cf..6e0f192a 100644 --- a/src/java/ognl/OgnlRuntime.java +++ b/src/java/ognl/OgnlRuntime.java @@ -1789,43 +1789,57 @@ public static Map getMethods(Class targetClass, boolean staticMethods) if ((result = (Map) cache.get(targetClass)) == null) { result = new HashMap(23); - - 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 defaul methods - toExamined.addAll(Arrays.asList(c.getInterfaces())); + collectMethods(targetClass, result, staticMethods); + cache.put(targetClass, result); + } + } + } + return result; } - for (Class c : toExamined) - { - Method[] ma = c.getDeclaredMethods(); + private static void collectMethods(Class c, Map result, boolean staticMethods) { + 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 (int i = 0, icount = ma.length; i < icount; i++) - { - // skip over synthetic methods + // skip over synthetic methods + if (!isMethodCallable(ma[i])) + continue; - if (!isMethodCallable(ma[i])) - continue; + if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods) + addMethodToResult(result, ma[i]); + } - if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods) - { - List ml = (List) result.get(ma[i].getName()); + Class superclass = c.getSuperclass(); + if (superclass != null) + collectMethods(superclass, result, staticMethods); - if (ml == null) - result.put(ma[i].getName(), ml = new ArrayList()); + for (Class iface : c.getInterfaces()) + collectMethods(iface, result, staticMethods); + } - ml.add(ma[i]); - } - } - } - cache.put(targetClass, result); - } - } - } - return result; + 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); + } + + /** + * 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 85563d19..787121ed 100644 --- a/src/test/java/ognl/Java8Test.java +++ b/src/test/java/ognl/Java8Test.java @@ -22,9 +22,11 @@ public void testDefaultMethodOnSubClass() { class SubClassWithDefaults extends ClassWithDefaults { + public String getName() { return "name"; } + } -class ClassWithDefaults /* implements InterfaceWithDefaults */ { +class ClassWithDefaults /* implements SubInterfaceWithDefaults */ { } @@ -33,5 +35,8 @@ class ClassWithDefaults /* implements InterfaceWithDefaults */ { * interface InterfaceWithDefaults { default public void defaultMethod() { } + default public String getName() { return "name"; } +} +interface SubInterfaceWithDefaults extends InterfaceWithDefaults { } */