Giter VIP home page Giter VIP logo

Comments (6)

harawata avatar harawata commented on August 12, 2024 1

Thank you, @lukaszlenart !

Even when the java.lang.reflect.Method references the interface's method (i.e. I#doSth()), java.lang.reflect.Method#invoke() will return the correct value depending on the first argument (i.e. the target instance).
It should be OK if the following test passes, right?

@Test
public void should() throws Exception {
    Map defaultContext = new HashMap<>();
    Map<String, Object> root = new HashMap<>();
    root.put("a", new A());
    root.put("b", new B());
    assertTrue((Boolean) Ognl.getValue("a.doSth()", defaultContext, root));
    assertFalse((Boolean) Ognl.getValue("b.doSth()", defaultContext, root));
}

Please let me know if I am misunderstanding the issue.

from ognl.

lukaszlenart avatar lukaszlenart commented on August 12, 2024 1

@harawata you are right, it's even clearer to call the public method in such case 👏

from ognl.

harawata avatar harawata commented on August 12, 2024

@Farbfetzen ,
Thank you for re-filing the issue.

@lukaszlenart ,
Here are some additional info.

The following test yields the "illegal reflective access" warning on Java 9+ and an exception on Java 16+ [1].

@Test
public void testMapContainsKey() throws Exception {
  Map defaultContext = new HashMap<>();
  Map<String, Object> root = new HashMap<>();
  root.put("map", Collections.singletonMap("key", "value"));
  assertTrue((Boolean) Ognl.getValue("map.containsKey('key')", defaultContext, root));
}

This happens because OGNL calls the containsKey() method of the private class java.util.Collections$SingletonMap.
The method OGNL should call is the one that is defined in java.util.Map.

The comment on the relevant line seems to imply that this behavior is intentional, but can you think of a case where it is necessary (or more appropriate) to call "the most specific" method rather than the same method defined in the superclass/interface? (there seems to be no test case)
I'm working on a fix which basically alters the priority when choosing the method to call.

[1] Stack Trace
java.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.Collections$SingletonMap.containsKey(java.lang.Object) accessible: module java.base does not "opens java.util" to unnamed module @11739fa6
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
	at ognl.AccessibleObjectHandlerPreJDK9.setAccessible(AccessibleObjectHandlerPreJDK9.java:58)
	at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:1211)
	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1962)
	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:2038)
	at ognl.ASTMethod.getValueBody(ASTMethod.java:97)
	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
	at ognl.SimpleNode.getValue(SimpleNode.java:258)
	at ognl.ASTChain.getValueBody(ASTChain.java:141)
	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
	at ognl.SimpleNode.getValue(SimpleNode.java:258)
	at ognl.Ognl.getValue(Ognl.java:586)
	at ognl.Ognl.getValue(Ognl.java:688)
	at ognl.Ognl.getValue(Ognl.java:658)
	at ognl_default_method.OgnlDefaultMethodTest.testMapContainsKey(OgnlDefaultMethodTest.java:97)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

from ognl.

lukaszlenart avatar lukaszlenart commented on August 12, 2024

Probably in case of interfaces it makes sense to call interface version, but I think we also need to cover the below case

interface I {
  boolean doSth();
}

class A implements I {
  public boolean doSth() { return true ; }
}

class B extends A {
  public boolean doSth() { return false; }
}

from ognl.

lukaszlenart avatar lukaszlenart commented on August 12, 2024

I think you are right, but we can try to play with the scoring to score private methods lower - maybe that will solve the problem.

from ognl.

harawata avatar harawata commented on August 12, 2024

@lukaszlenart ,

I found a case where calling subclass method is more appropriate.

@Test
public void shouldInvokeSyntheticBridgeMethod() throws Exception {
    StringBuilder root = new StringBuilder("abc");
    Assert.assertEquals((int) 'b',
            Ognl.getValue("codePointAt(1)", defaultContext, root));
}

I had considered tweaking the score, but this comparison seems to make sense only when two methods have the same score and (almost) same signature.
So, for now, the plan is to use the public one over non-public one.
Please take a look at #144 when you have time.

from ognl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.