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

Can't call methods of private subclasses in a module #5894

Closed
yamam opened this issue Sep 27, 2019 · 3 comments · Fixed by #6069
Closed

Can't call methods of private subclasses in a module #5894

yamam opened this issue Sep 27, 2019 · 3 comments · Fixed by #6069

Comments

@yamam
Copy link

@yamam yamam commented Sep 27, 2019

Fixed an issue in #5841 where private subclasses could not be accessed.
However, the error still occurs if the class belongs to a module.

Environment

$ java --version
openjdk 11.0.4 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)

jruby-complete-9.2.9.0-20190926.210253-53.jar

JavaTest.java

package test;

public class JavaTest {
    public interface PublicInterface {
        public void publicMethod(Integer a);
        public void publicMethod(Long a);
    }

    public PublicInterface publicMember = new PrivateSubclass();

    private class PrivateSubclass implements PublicInterface {
        public void publicMethod(Integer a) {System.out.println("PrivateSubclass.publicMethod(Integer)");}
        public void publicMethod(Long a) {System.out.println("PrivateSubclass.publicMethod(Long)");}
    }
}

module-info.java

module test {
    exports test;
}

JavaMain.java

import test.JavaTest;
import org.jruby.embed.ScriptingContainer;
public class JavaMain {
  public static void main(String[] args) {
    new JavaTest().publicMember.publicMethod(1);
    new ScriptingContainer().runScriptlet("java_import 'test.JavaTest'; JavaTest.new.publicMember.publicMethod(1)");
    new ScriptingContainer().runScriptlet("java_import 'test.JavaTest'; JavaTest.new.publicMember.java_method(:publicMethod, [java.lang.Integer.java_class]).call(1)");
  }
}

Expected Behavior

$ javac -d mods/test module-info.java JavaTest.java
$ javac --module-path mods --add-modules test -cp jruby-complete.jar JavaMain.java
$ java --module-path mods --add-modules test -cp .:jruby-complete.jar JavaMain
PrivateSubclass.publicMethod(Integer)
PrivateSubclass.publicMethod(Long)
PrivateSubclass.publicMethod(Integer)

Actual Behavior

$ javac -d mods/test module-info.java JavaTest.java
$ javac --module-path mods --add-modules test -cp jruby-complete.jar JavaMain.java
$ java --module-path mods --add-modules test -cp .:jruby-complete.jar JavaMain
PrivateSubclass.publicMethod(Integer)
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.headius.backport9.modules.Modules (jruby-complete.jar) to method sun.nio.ch.NativeThread.signal(long)
WARNING: Please consider reporting this to the maintainers of com.headius.backport9.modules.Modules
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
TypeError: illegal access on 'publicMethod': class org.jruby.javasupport.JavaMethod cannot access a member of class test.JavaTest$PrivateSubclass (in module test) with modifiers "public"
  <main> at <script>:1
Exception in thread "main" org.jruby.embed.EvalFailedException: (TypeError) illegal access on 'publicMethod': class org.jruby.javasupport.JavaMethod cannot access a member of class test.JavaTest$PrivateSubclass (in module test) with modifiers "public"
        at org.jruby.embed.internal.EmbedEvalUnitImpl.run(EmbedEvalUnitImpl.java:131)
        at org.jruby.embed.ScriptingContainer.runUnit(ScriptingContainer.java:1295)
        at org.jruby.embed.ScriptingContainer.runScriptlet(ScriptingContainer.java:1288)
        at JavaMain.main(JavaMain.java:7)
Caused by: org.jruby.exceptions.TypeError: (TypeError) illegal access on 'publicMethod': class org.jruby.javasupport.JavaMethod cannot access a member of class test.JavaTest$PrivateSubclass (in module test) with modifiers "public"
        at RUBY.<main>(<script>:1)
@headius
Copy link
Member

@headius headius commented Sep 27, 2019

Thank you for the complete repro...I'll have a look.

@headius headius added this to the JRuby 9.2.10.0 milestone Oct 29, 2019
@headius
Copy link
Member

@headius headius commented Feb 15, 2020

Ok so calling the method directly works correctly, but java_method is not doing the right thing.

I guess this is open for a bit of discussion here. I suspect that java_method worked before because it set the method accessible, but under a module world that's not generally ok. So then the question is what it should do.

I'm leaning toward making java_method and friends try to find the highest public definition of the method, just as method dispatch would do. But this would not exactly match the original behavior, which was more of a brute force "make this method callable" sort of thing.

@headius
Copy link
Member

@headius headius commented Feb 15, 2020

Yes, I see the problem now.

The logic for java_method and other one-off method grabbers goes through a different path than the logic for gathering and binding all methods on a given class. The latter has had various tweaks and updates to support modules, to search for the appropriate public superclass or superinterface method when a class is not public, etc. We will need to look into using that logic for java_method.

headius added a commit to headius/jruby that referenced this issue Feb 15, 2020
This search logic was only being used when binding all the methods
for a Java class in Ruby space, while the one-off accessors like
`java_method` went through different logic. The latter logic has
never been updated to work properly under the new module regime,
which led to bugs like jruby#5894 that would attempt to invoke private
or otherwise inaccessible methods rather than continuing to search
for a public version.

This patch opens up the accessible-only method search from
MethodGatherer so it can be reused for the one-off forms.

Fixes jruby#5894
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

2 participants