diff --git a/src/main/java/ognl/OgnlRuntime.java b/src/main/java/ognl/OgnlRuntime.java index 2b504882..20cc35ed 100644 --- a/src/main/java/ognl/OgnlRuntime.java +++ b/src/main/java/ognl/OgnlRuntime.java @@ -1782,22 +1782,15 @@ private static MatchingMethod findBestMethod(List methods, Class typeClass, Stri failure = null; } else if (mm.score == score) { // it happens that we see the same method signature multiple times - for the current class or interfaces ... - // TODO why are all of them on the list and not only the most specific one? // check for same signature if (Arrays.equals(mm.mMethod.getParameterTypes(), m.getParameterTypes()) && mm.mMethod.getName().equals(m.getName())) { boolean retsAreEqual = mm.mMethod.getReturnType().equals(m.getReturnType()); - // it is the same method. we use the most specific one... - if (mm.mMethod.getDeclaringClass().isAssignableFrom(m.getDeclaringClass())) { - if (!retsAreEqual && !mm.mMethod.getReturnType().isAssignableFrom(m.getReturnType())) - System.err.println("Two methods with same method signature but return types conflict? \""+mm.mMethod+"\" and \""+m+"\" please report!"); - + // it is the same method. we use the public one... + if (!Modifier.isPublic(mm.mMethod.getDeclaringClass().getModifiers()) + && Modifier.isPublic(m.getDeclaringClass().getModifiers())) { mm = new MatchingMethod(m, score, report, mParameterTypes); failure = null; - } else if (!m.getDeclaringClass().isAssignableFrom(mm.mMethod.getDeclaringClass())) { - // this should't happen - System.err.println("Two methods with same method signature but not providing classes assignable? \""+mm.mMethod+"\" and \""+m+"\" please report!"); - } else if (!retsAreEqual && !m.getReturnType().isAssignableFrom(mm.mMethod.getReturnType())) - System.err.println("Two methods with same method signature but return types conflict? \""+mm.mMethod+"\" and \""+m+"\" please report!"); + } } else { // two methods with same score - direct compare to find the better one... // legacy wins over varargs @@ -2253,15 +2246,7 @@ private static void collectMethods(Class c, Map result, boolean staticMethods) { } for (int i = 0, icount = ma.length; i < icount; i++) { - if (c.isInterface()) - { - if (isDefaultMethod(ma[i])) - addMethodToResult(result, ma[i]); - continue; - } - - // skip over synthetic methods - if (!isMethodCallable(ma[i])) + if (!isMethodCallable_BridgeOrNonSynthetic(ma[i])) continue; if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods) diff --git a/src/test/java/ognl/OgnlRuntimeTest.java b/src/test/java/ognl/OgnlRuntimeTest.java index 4c12dcf4..b447e76a 100644 --- a/src/test/java/ognl/OgnlRuntimeTest.java +++ b/src/test/java/ognl/OgnlRuntimeTest.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; @@ -548,4 +549,64 @@ public Integer getIndex() { } } + @Test + public void shouldInvokeSyntheticBridgeMethod() throws Exception { + StringBuilder root = new StringBuilder("abc"); + Assert.assertEquals((int) 'b', + Ognl.getValue("codePointAt(1)", defaultContext, root)); + } + + @Test + public void shouldInvokeSuperclassMethod() throws Exception { + Map root = Collections.singletonMap(3L, 33L); + Assert.assertTrue((Boolean) Ognl.getValue("containsKey(3L)", + defaultContext, root)); + } + + @Test + public void shouldInvokeInterfaceMethod() throws Exception { + Assert.assertTrue((Boolean) Ognl.getValue("isEmpty()", defaultContext, + Collections.checkedCollection(new ArrayList<>(), String.class))); + } + + public interface I1 { + Integer getId(); + } + + public interface I2 { + Integer getId(); + } + + @Test + public void shouldMultipleInterfaceWithTheSameMethodBeFine() + throws Exception { + class C1 implements I1, I2 { + public Integer getId() { + return 100; + } + } + Assert.assertEquals(100, + Ognl.getValue("getId()", defaultContext, new C1())); + } + + public interface I3 { + T get(); + } + + public interface I4 { + Long get(); + } + + @Test + public void shouldTwoMethodsWithDifferentReturnTypeBeFine() + throws Exception { + class C1 implements I3, I4 { + @Override + public Long get() { + return 3L; + } + } + Assert.assertEquals(3L, + Ognl.getValue("get()", defaultContext, new C1())); + } }