Skip to content

Java integration should call toJava or to_int for array index and value #2658

Closed
@InfraRuby

Description

@InfraRuby

Java integration does not support int-like objects:

class I
    def initialize(value)
        @value = value
        return
    end
    def to_int
        return @value
    end
end

n = I.new(2)
a = Java::byte[n].new   # works: JRuby calls n.to_int

value = I.new(1)
a[1] = value            # fails with TypeError: JRuby calls value.toJava(Byte.class)

index = I.new(1)
a[index]                # fails with TypeError: JRuby expects RubyInteger or RubyRange

index = I.new(1)
a[index] = 1            # fails with ClassCastException: JRuby casts index to RubyInteger

It's also a problem for InfraRuby compatibility:

require "infraruby-java"

n = Int32[2]
a = Java::byte[n].new   # works: JRuby calls n.to_int

value = Byte[1]
a[1] = value            # works: JRuby calls value.toJava(Byte.class)

index = Int32[1]
a[index]                # fails with TypeError: JRuby expects RubyInteger or RubyRange

index = Int32[1]
a[index] = 1            # fails with ClassCastException: JRuby casts index to RubyInteger

A patch for core/src/main/java/org/jruby/RubyBasicObject.java:

@@ -833,6 +833,10 @@
             return this;
         }

+        RubyConverter converter = JavaUtil.RUBY_CONVERTERS.get(target);
+        if (converter != null) {
+            return converter.convert(getRuntime().getCurrentContext(), this);
+        }
         throw getRuntime().newTypeError("cannot convert instance of " + getClass() + " to " + target);
     }

A patch for core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java:

@@ -73,19 +73,19 @@

     @JRubyMethod(name = "[]")
     public IRubyObject op_aref(ThreadContext context, IRubyObject arg) {
-        if (arg instanceof RubyInteger) {
-            int index = (int)((RubyInteger)arg).getLongValue();
-            return ArrayUtils.arefDirect(context.runtime, getObject(), converter, index);
-        } else {
+        if (arg instanceof RubyRange) {
             return getRange(context, arg);
+        } else {
+            int i = arg.toJava(Integer.class);
+            return ArrayUtils.arefDirect(context.runtime, getObject(), converter, i);
         }
     }

     @JRubyMethod(name = "[]", required = 1, rest = true)
     public IRubyObject op_aref(ThreadContext context, IRubyObject[] args) {
-        if (args.length == 1 && args[0] instanceof RubyInteger) {
-            int index = (int)((RubyInteger)args[0]).getLongValue();
-            return ArrayUtils.arefDirect(context.runtime, getObject(), converter, index);
+        if (args.length == 1) {
+            IRubyObject arg = args[0];
+            return op_aref(context, arg);
         } else {
             return getRange(context, args);
         }
@@ -93,7 +93,8 @@

     @JRubyMethod(name = "[]=")
     public IRubyObject op_aset(ThreadContext context, IRubyObject index, IRubyObject value) {
-        ArrayUtils.asetDirect(context.runtime, getObject(), converter, (int)((RubyInteger)index).getLongValue(), value);
+        int i = index.toJava(Integer.class);
+        ArrayUtils.asetDirect(context.runtime, getObject(), converter, i, value);
         return value;
     }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions