Skip to content

Commit

Permalink
Fixes to make explicitly passing a Java array as the last argument to…
Browse files Browse the repository at this point in the history
… a varargs method work like it did before with varargs support still in place.
  • Loading branch information
headius committed Dec 30, 2009
1 parent f2ff19f commit 4f9b2a3
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 83 deletions.
46 changes: 24 additions & 22 deletions spec/java_integration/fixtures/ClassWithVarargs.java
@@ -1,46 +1,48 @@
package java_integration.fixtures;

import java.util.Arrays;

public class ClassWithVarargs {
private int constructor;
private String constructor;
public ClassWithVarargs(Object... args) {
constructor = 0;
constructor = "0: " + Arrays.toString(args);
}
public ClassWithVarargs(String a, Object... args) {
constructor = 1;
constructor = "1: " + Arrays.toString(args);
}
public ClassWithVarargs(String a, String b, Object... args) {
constructor = 2;
constructor = "2: " + Arrays.toString(args);
}
public ClassWithVarargs(String a, String b, String c, Object... args) {
constructor = 3;
constructor = "3: " + Arrays.toString(args);
}
public int getConstructor() {
public String getConstructor() {
return constructor;
}

public static int varargsStatic(Object... args) {
return 0;
public static String varargsStatic(Object... args) {
return "0: " + Arrays.toString(args);
}
public static int varargsStatic(String a, Object... args) {
return 1;
public static String varargsStatic(String a, Object... args) {
return "1: " + Arrays.toString(args);
}
public static int varargsStatic(String a, String b, Object... args) {
return 2;
public static String varargsStatic(String a, String b, Object... args) {
return "2: " + Arrays.toString(args);
}
public static int varargsStatic(String a, String b, String c, Object... args) {
return 3;
public static String varargsStatic(String a, String b, String c, Object... args) {
return "3: " + Arrays.toString(args);
}

public int varargs(Object... args) {
return 0;
public String varargs(Object... args) {
return "0: " + Arrays.toString(args);
}
public int varargs(String a, Object... args) {
return 1;
public String varargs(String a, Object... args) {
return "1: " + Arrays.toString(args);
}
public int varargs(String a, String b, Object... args) {
return 2;
public String varargs(String a, String b, Object... args) {
return "2: " + Arrays.toString(args);
}
public int varargs(String a, String b, String c, Object... args) {
return 3;
public String varargs(String a, String b, String c, Object... args) {
return "3: " + Arrays.toString(args);
}
}
118 changes: 70 additions & 48 deletions spec/java_integration/methods/dispatch_spec.rb
Expand Up @@ -126,183 +126,205 @@
it "should be called with the most exact overload" do
lambda do
obj = ClassWithVarargs.new(1)
obj.constructor.should == 0;
obj.constructor.should == "0: [1]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new(1,2)
obj.constructor.should == 0;
obj.constructor.should == "0: [1, 2]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new(1,2,3)
obj.constructor.should == 0;
obj.constructor.should == "0: [1, 2, 3]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new(1,2,3,4)
obj.constructor.should == 0;
obj.constructor.should == "0: [1, 2, 3, 4]"
end.should_not raise_error

lambda do
obj = ClassWithVarargs.new('foo', 1)
obj.constructor.should == 1;
obj.constructor.should == "1: [1]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 1, 2)
obj.constructor.should == 1;
obj.constructor.should == "1: [1, 2]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 1, 2, 3)
obj.constructor.should == 1;
obj.constructor.should == "1: [1, 2, 3]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 1, 2, 3, 4)
obj.constructor.should == 1;
obj.constructor.should == "1: [1, 2, 3, 4]"
end.should_not raise_error

lambda do
obj = ClassWithVarargs.new('foo', 'bar', 1)
obj.constructor.should == 2;
obj.constructor.should == "2: [1]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 1, 2)
obj.constructor.should == 2;
obj.constructor.should == "2: [1, 2]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 1, 2, 3)
obj.constructor.should == 2;
obj.constructor.should == "2: [1, 2, 3]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 1, 2, 3, 4)
obj.constructor.should == 2;
obj.constructor.should == "2: [1, 2, 3, 4]"
end.should_not raise_error

lambda do
obj = ClassWithVarargs.new('foo', 'bar', 'baz', 1)
obj.constructor.should == 3;
obj.constructor.should == "3: [1]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 'baz', 1, 2)
obj.constructor.should == 3;
obj.constructor.should == "3: [1, 2]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 'baz', 1, 2, 3)
obj.constructor.should == 3;
obj.constructor.should == "3: [1, 2, 3]"
end.should_not raise_error
lambda do
obj = ClassWithVarargs.new('foo', 'bar', 'baz', 1, 2, 3, 4)
obj.constructor.should == 3;
obj.constructor.should == "3: [1, 2, 3, 4]"
end.should_not raise_error
end

it "should be callable with an array" do
ClassWithVarargs.new([1,2,3].to_java).constructor.should == "0: [1, 2, 3]"
ClassWithVarargs.new('foo', [1,2,3].to_java).constructor.should == "1: [1, 2, 3]"
ClassWithVarargs.new('foo', 'bar', [1,2,3].to_java).constructor.should == "2: [1, 2, 3]"
ClassWithVarargs.new('foo', 'bar', 'baz', [1,2,3].to_java).constructor.should == "3: [1, 2, 3]"
end
end

describe "A class with varargs instance methods" do
it "should be called with the most exact overload" do
obj = ClassWithVarargs.new(1)
lambda do
obj.varargs(1).should == 0;
obj.varargs(1).should == "0: [1]";
end.should_not raise_error
lambda do
obj.varargs(1,2).should == 0;
obj.varargs(1,2).should == "0: [1, 2]";
end.should_not raise_error
lambda do
obj.varargs(1,2,3).should == 0;
obj.varargs(1,2,3).should == "0: [1, 2, 3]";
end.should_not raise_error
lambda do
obj.varargs(1,2,3,4).should == 0;
obj.varargs(1,2,3,4).should == "0: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
obj.varargs('foo', 1).should == 1;
obj.varargs('foo', 1).should == "1: [1]";
end.should_not raise_error
lambda do
obj.varargs('foo', 1, 2).should == 1;
obj.varargs('foo', 1, 2).should == "1: [1, 2]";
end.should_not raise_error
lambda do
obj.varargs('foo', 1, 2, 3).should == 1;
obj.varargs('foo', 1, 2, 3).should == "1: [1, 2, 3]";
end.should_not raise_error
lambda do
obj.varargs('foo', 1, 2, 3, 4).should == 1;
obj.varargs('foo', 1, 2, 3, 4).should == "1: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
obj.varargs('foo', 'bar', 1).should == 2;
obj.varargs('foo', 'bar', 1).should == "2: [1]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 1, 2).should == 2;
obj.varargs('foo', 'bar', 1, 2).should == "2: [1, 2]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 1, 2, 3).should == 2;
obj.varargs('foo', 'bar', 1, 2, 3).should == "2: [1, 2, 3]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 1, 2, 3, 4).should == 2;
obj.varargs('foo', 'bar', 1, 2, 3, 4).should == "2: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
obj.varargs('foo', 'bar', 'baz', 1).should == 3;
obj.varargs('foo', 'bar', 'baz', 1).should == "3: [1]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 'baz', 1, 2).should == 3;
obj.varargs('foo', 'bar', 'baz', 1, 2).should == "3: [1, 2]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 'baz', 1, 2, 3).should == 3;
obj.varargs('foo', 'bar', 'baz', 1, 2, 3).should == "3: [1, 2, 3]";
end.should_not raise_error
lambda do
obj.varargs('foo', 'bar', 'baz', 1, 2, 3, 4).should == 3;
obj.varargs('foo', 'bar', 'baz', 1, 2, 3, 4).should == "3: [1, 2, 3, 4]";
end.should_not raise_error
end

it "should be callable with an array" do
obj = ClassWithVarargs.new(1)
obj.varargs([1,2,3].to_java).should == "0: [1, 2, 3]"
obj.varargs('foo', [1,2,3].to_java).should == "1: [1, 2, 3]"
obj.varargs('foo', 'bar', [1,2,3].to_java).should == "2: [1, 2, 3]"
obj.varargs('foo', 'bar', 'baz', [1,2,3].to_java).should == "3: [1, 2, 3]"
end
end

describe "A class with varargs static methods" do
it "should be called with the most exact overload" do
lambda do
ClassWithVarargs.varargs_static(1).should == 0;
ClassWithVarargs.varargs_static(1).should == "0: [1]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static(1,2).should == 0;
ClassWithVarargs.varargs_static(1,2).should == "0: [1, 2]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static(1,2,3).should == 0;
ClassWithVarargs.varargs_static(1,2,3).should == "0: [1, 2, 3]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static(1,2,3,4).should == 0;
ClassWithVarargs.varargs_static(1,2,3,4).should == "0: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
ClassWithVarargs.varargs_static('foo', 1).should == 1;
ClassWithVarargs.varargs_static('foo', 1).should == "1: [1]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 1, 2).should == 1;
ClassWithVarargs.varargs_static('foo', 1, 2).should == "1: [1, 2]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 1, 2, 3).should == 1;
ClassWithVarargs.varargs_static('foo', 1, 2, 3).should == "1: [1, 2, 3]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 1, 2, 3, 4).should == 1;
ClassWithVarargs.varargs_static('foo', 1, 2, 3, 4).should == "1: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 1).should == 2;
ClassWithVarargs.varargs_static('foo', 'bar', 1).should == "2: [1]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2).should == 2;
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2).should == "2: [1, 2]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2, 3).should == 2;
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2, 3).should == "2: [1, 2, 3]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2, 3, 4).should == 2;
ClassWithVarargs.varargs_static('foo', 'bar', 1, 2, 3, 4).should == "2: [1, 2, 3, 4]";
end.should_not raise_error

lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1).should == 3;
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1).should == "3: [1]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2).should == 3;
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2).should == "3: [1, 2]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2, 3).should == 3;
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2, 3).should == "3: [1, 2, 3]";
end.should_not raise_error
lambda do
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2, 3, 4).should == 3;
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', 1, 2, 3, 4).should == "3: [1, 2, 3, 4]";
end.should_not raise_error
end

it "should be callable with an array" do
ClassWithVarargs.varargs_static([1,2,3].to_java).should == "0: [1, 2, 3]"
ClassWithVarargs.varargs_static('foo', [1,2,3].to_java).should == "1: [1, 2, 3]"
ClassWithVarargs.varargs_static('foo', 'bar', [1,2,3].to_java).should == "2: [1, 2, 3]"
ClassWithVarargs.varargs_static('foo', 'bar', 'baz', [1,2,3].to_java).should == "3: [1, 2, 3]"
end
end
8 changes: 7 additions & 1 deletion src/org/jruby/RubyInstanceConfig.java
Expand Up @@ -243,6 +243,10 @@ public boolean shouldPrecompileAll() {
public static final boolean JIT_CACHE_ENABLED
= SafePropertyAccessor.getBoolean("jruby.jit.cache", true);

public static final boolean REFLECTED_HANDLES
= SafePropertyAccessor.getBoolean("jruby.reflected.handles", false)
|| SafePropertyAccessor.getBoolean("jruby.reflection", false);

public static interface LoadServiceCreator {
LoadService create(Ruby runtime);

Expand Down Expand Up @@ -529,7 +533,9 @@ public String getPropertyHelp() {
.append(" jruby.debug.launch=true|false\n")
.append(" ShellLauncher logging\n")
.append(" jruby.debug.fullTrace=true|false\n")
.append(" Set whether full traces are enabled (c-call/c-return). Default is false.\n");
.append(" Set whether full traces are enabled (c-call/c-return). Default is false.\n")
.append(" jruby.reflected.handles=true|false\n")
.append(" Use reflection for binding methods, not generated bytecode. Default is false.\n");

return sb.toString();
}
Expand Down
4 changes: 2 additions & 2 deletions src/org/jruby/RubyModule.java
Expand Up @@ -637,8 +637,8 @@ public Map<String, List<JavaMethodDescriptor>> getStaticAnnotatedMethods1_9() {
public void defineAnnotatedMethodsIndividually(Class clazz) {
TypePopulator populator;

if (RubyInstanceConfig.FULL_TRACE_ENABLED) {
// we need full traces, use default (slow) populator
if (RubyInstanceConfig.FULL_TRACE_ENABLED || RubyInstanceConfig.REFLECTED_HANDLES) {
// we want reflected invokers or need full traces, use default (slow) populator
if (DEBUG) System.out.println("trace mode, using default populator");
populator = TypePopulator.DEFAULT;
} else {
Expand Down
17 changes: 13 additions & 4 deletions src/org/jruby/java/invokers/RubyToJavaInvoker.java
Expand Up @@ -13,6 +13,7 @@
import org.jruby.RubyModule;
import org.jruby.internal.runtime.methods.JavaMethod;
import org.jruby.java.dispatch.CallableSelector;
import org.jruby.java.proxies.ArrayJavaProxy;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.JavaCallable;
import org.jruby.runtime.Arity;
Expand Down Expand Up @@ -116,13 +117,21 @@ static Object convertArg(ThreadContext context, IRubyObject arg, JavaCallable me

static Object convertVarargs(ThreadContext context, IRubyObject[] args, JavaCallable method) {
Class[] types = method.getParameterTypes();
Class varargType = types[types.length - 1].getComponentType();
Class varargArrayType = types[types.length - 1];
Class varargType = varargArrayType.getComponentType();
int varargsStart = types.length - 1;
int varargsCount = args.length - varargsStart;
Object varargs = Array.newInstance(varargType, varargsCount);

for (int i = 0; i < varargsCount; i++) {
Array.set(varargs, i, args[varargsStart + i].toJava(varargType));
Object varargs;
if (varargsCount == 1 && args[varargsStart] instanceof ArrayJavaProxy) {
// we may have a pre-created array to pass; try that first
varargs = args[varargsStart].toJava(varargArrayType);
} else {
varargs = Array.newInstance(varargType, varargsCount);

for (int i = 0; i < varargsCount; i++) {
Array.set(varargs, i, args[varargsStart + i].toJava(varargType));
}
}
return varargs;
}
Expand Down

0 comments on commit 4f9b2a3

Please sign in to comment.