Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid illegal reflective access when possible #144

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 5 additions & 20 deletions src/main/java/ognl/OgnlRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
61 changes: 61 additions & 0 deletions src/test/java/ognl/OgnlRuntimeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Long, Long> 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> {
T get();
}

public interface I4 {
Long get();
}

@Test
public void shouldTwoMethodsWithDifferentReturnTypeBeFine()
throws Exception {
class C1 implements I3<Long>, I4 {
@Override
public Long get() {
return 3L;
}
}
Assert.assertEquals(3L,
Ognl.getValue("get()", defaultContext, new C1()));
}
}