JRuby ignores java access modifiers - bug or feature?

Hi,

using JRuby 1.5.1 I am getting in trouble because it seems that JRuby is
not aware of Java accessibility when determining method binding.

With the following Java program

package a;
public class A {
public void m(Object o) {
System.out.println(“Object”);
}
private void m(String s) {
System.out.println(“String”);
}
}

and the Ruby script

require ‘D:/…’
a = Java::a::A.new()
a.m(‘abc’)

the result is

String

where a Java call

A a = new A();
a.m(“abc”);

would evaluate to

Object

It seems that Ruby ignores the Java accessibility levels. From a general
point of view it might be seen as a feature but in my example above it
turns out to be a bug.

Is this behaviour intended or still a bug? I have not found any issues
in Jira according to this.

Cheers

Andreas


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, Aug 4, 2010 at 3:28 AM, Andreas Thies
[email protected] wrote:

System.out.println(“Object”);
a.m(‘abc’)
would evaluate to

Object

It seems that Ruby ignores the Java accessibility levels. From a general
point of view it might be seen as a feature but in my example above it
turns out to be a bug.

Is this behaviour intended or still a bug? I have not found any issues
in Jira according to this.

It’s either depending on your point of view. This is certainly an edge
case we have not accounted for before. Generally we try to make as
much of Java easily accessible from Ruby as possible. This includes
private fields and methods. Maybe it’s the case that we’re too eager
with them, although in your example I suspect that it has nothing to
do with whether you can call the private overload of #m directly but
that we get all the #m overloads and choose the best based on type,
without regard for visibility.

It’s probably worthwhile to file a bug with your example, and we can
continue the discussion on how JRuby should handle it.

/Nick


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

It is also worth pointing out that when you don’t get the overload you
want then you can still use java_send, jave_method, or java_alias to
get access to the Java method you want.

http://kenai.com/projects/jruby/pages/CallingJavaFromJRuby#Calling_masked_or_unreachable_Java_methods_with_java_send

Even if we do change method resolution for private at some point in
the future, these methods are still handy since we don’t have a true
1-1 mapping between Ruby and Java types.

-Tom

On Wed, Aug 4, 2010 at 11:17 AM, Nick S. [email protected]
wrote:

public class A {
require ‘D:/…’
a.m(“abc”);
in Jira according to this.
It’s probably worthwhile to file a bug with your example, and we can


blog: http://blog.enebo.com twitter: tom_enebo
mail: [email protected]


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, Aug 4, 2010 at 3:28 AM, Andreas Thies
[email protected] wrote:

  System.out.println(“Object”);
a.m(‘abc’)
would evaluate to

Object

The problem is that we live in two worlds.

In one world, people want to be able to call any method on any Java
object, and so we make protected and private methods available since
we can’t tell whether it might be a valid case (like if you re-opened
a Java class with a private method and wanted to call it…that should
work, right?).

In the other world, security restrictions prevent us from exposing
private and protected methods, so we only expose public methods
(because that’s all we can do).

So basically, we expose private and protected methods when possible
because it’s required for some cases and desired for others. In this
case, it’s obviously getting in your way, but it would get in your way
if you were calling the method from within the same class; you’d need
to cast to Object to force a specific target. That’s what java_send
and friends can do, since you specify a Java signature to go with your
call.

I’m not sure there’s a perfect solution for this. We don’t know from
the source of the call whether you intend to only call public methods
or whether you intend to call any methods that might reasonably be
visible. Even in the latter case, it’s hard to know what should
“reasonably be visible” since Ruby’s class structures don’t map
exactly to Java structures.

I assume you’d want this case to call the Object method. The problem
is someone else might want it to call the String method. Who’s right?

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, Aug 4, 2010 at 3:28 AM, Andreas Thies
[email protected] wrote:

System.out.println(“Object”);
a.m(‘abc’)
would evaluate to
Cheers

Andreas

Interesting. I always assumed access specifiers were enforced by the
JVM, not by Java itself.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Aug 6, 2010 at 5:26 AM, Charles Oliver N.
[email protected] wrote:

They are, but if security policies for the current JVM allow it, you
can ask it to disable visibility checks and reflectively call or
manipulate any method or field. It’s just not reliable that the
policies will be so open, and therefore we need the fallback case that
doesn’t depend upon it.

This is what we are doing, so this particular issue hasn’t bitten us.

At least, not until today, where I was running from the IDE (i.e.
security is disabled), and got this gem:

module Item
  def descendants
    children.map { |child| [ child ] + child.descendants }.flatten
  end
end

But unfortunately, the list has a protected method like this:

    protected abstract T map(F element);

Generics are erased at runtime though, so all the JVM sees is:

    protected abstract Object map(Object element);

And RubyProc is an Object, so it tries calling it, of course, with the
following result:

com/acme/MyMappedList.java:13:in `map’: java.lang.ClassCastException:
org.jruby.RubyProc cannot be cast to com.acme.blah.PrivateClass
(NativeException)

It would be nice to be able to simulate reduced permissions by way
of a system property… it’s either that or I’ll have to set up the
run targets from the IDE to use the security policy (that might not be
a bad idea anyway though.)

TX


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Thu, Aug 5, 2010 at 10:39 AM, Eric C.
[email protected] wrote:

Interesting. I always assumed access specifiers were enforced by the
JVM, not by Java itself.

They are, but if security policies for the current JVM allow it, you
can ask it to disable visibility checks and reflectively call or
manipulate any method or field. It’s just not reliable that the
policies will be so open, and therefore we need the fallback case that
doesn’t depend upon it.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Charles Oliver N. wrote:

So basically, we expose private and protected methods when possible
because it’s required for some cases and desired for others. In this
case, it’s obviously getting in your way, (…)

I hardly can imagine cases where you depend on accessing a private
declaration. It’s inaccessible from the Java side (okay, there is
reflection but everyone will instantly notice that there is a dirty hack
present) so why should it work on the Ruby side in a way nobody reading
you code will notice that you access something in a way it was not
intended? Nevertheless, I fully for protected members.

I assume you’d want this case to call the Object method. The problem
is someone else might want it to call the String method. Who’s right?

You have pointed out the problem quite well.

From my point of view (coming from the Java side) JRuby’s behaviour was
quite unexpected. From a ruby programmers point of view it seems
desirable to get enhanced access.

Actually, I am doing research on cross language refactoring tools. So
for me it would have been nice to see the binding rules of JRuby and
Java match. They don’t, so my tool has to reflect that.

Cheers

Andreas


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Tue, Aug 10, 2010 at 11:37 PM, Trejkaz [email protected] wrote:

com/acme/MyMappedList.java:13:in `map’: java.lang.ClassCastException:
org.jruby.RubyProc cannot be cast to com.acme.blah.PrivateClass
(NativeException)

It would be nice to be able to simulate reduced permissions by way
of a system property… it’s either that or I’ll have to set up the
run targets from the IDE to use the security policy (that might not be
a bad idea anyway though.)

Yuck! Yeah, we decorate things like “map” onto collections at the
java.util.Collection level, so this protected method from a subclass
overwrites our version. That’s a tricky problem.

Providing a property to turn off the use of setAccessible is easy to
do, so I’ve done that on master (jruby.ji.setAccessible, 3916a17).

I’ve never liked using setAccessible to expose normal methods, since
it leads to problems like this (and it often gives a false impression
of what you can and cannot call from Ruby once you deploy your
application). There may be a way to only use it when it’s needed, but
that wouldn’t address cases like this where you might want the
protected map method to be available from within monkey-patched
methods added to that list’s class. But I don’t have a good answer :frowning:

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email