Skip to content

Commit

Permalink
Showing 56 changed files with 2,877 additions and 1,980 deletions.
6 changes: 4 additions & 2 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -90,7 +90,8 @@
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-enxio</artifactId>
<version>0.7</version>
<version>0.8-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
@@ -100,7 +101,8 @@
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>0.6</version>
<version>0.7-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
169 changes: 81 additions & 88 deletions core/src/main/java/org/jruby/java/addons/ArrayJavaAddons.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.java.addons;

import java.lang.reflect.Array;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyFixnum;
@@ -10,121 +9,115 @@
import org.jruby.runtime.builtin.IRubyObject;

public class ArrayJavaAddons {
@JRubyMethod
public static IRubyObject copy_data(
ThreadContext context, IRubyObject rubyArray, IRubyObject javaArray,
IRubyObject fillValue) {
JavaArray javaArrayJavaObj = (JavaArray)javaArray.dataGetStruct();

@JRubyMethod(name = "copy_data")
public static IRubyObject copy_data(final ThreadContext context,
final IRubyObject fromRuby, final IRubyObject toJava, final IRubyObject fillValue) {
JavaArray javaArray = (JavaArray) toJava.dataGetStruct();
final int javaLength = javaArray.getLength();
final Class<?> targetType = javaArray.getComponentType();

Object fillJavaObject = null;
int javaLength = (int)javaArrayJavaObj.length().getLongValue();
Class targetType = javaArrayJavaObj.getComponentType();

if (!fillValue.isNil()) {
fillJavaObject = fillValue.toJava(targetType);
}

RubyArray array = null;
int rubyLength;
if (rubyArray instanceof RubyArray) {
array = (RubyArray)rubyArray;
rubyLength = ((RubyArray)rubyArray).getLength();
if ( ! fillValue.isNil() ) fillJavaObject = fillValue.toJava(targetType);

RubyArray rubyArray = null;
if (fromRuby instanceof RubyArray) {
rubyArray = (RubyArray) fromRuby;
} else {
rubyLength = 0;
fillJavaObject = rubyArray.toJava(targetType);
fillJavaObject = fromRuby.toJava(targetType);
}

int i = 0;
for (; i < rubyLength && i < javaLength; i++) {
javaArrayJavaObj.setWithExceptionHandling(i, array.entry(i).toJava(targetType));
if ( rubyArray != null ) {
final int rubyLength = rubyArray.getLength();
for (; i < rubyLength && i < javaLength; i++) {
javaArray.setWithExceptionHandling(i, rubyArray.eltInternal(i).toJava(targetType));
}
}
if (i < javaLength && fillJavaObject != null) {
javaArrayJavaObj.fillWithExceptionHandling(i, javaLength, fillJavaObject);

if ( i < javaLength && fillJavaObject != null ) {
javaArray.fillWithExceptionHandling(i, javaLength, fillJavaObject);
}
return javaArray;

return toJava;
}
@JRubyMethod
public static IRubyObject copy_data_simple(
ThreadContext context, IRubyObject from, IRubyObject to) {
JavaArray javaArray = (JavaArray)to.dataGetStruct();
RubyArray rubyArray = (RubyArray)from;
copyDataToJavaArray(context, rubyArray, javaArray);
return to;

@JRubyMethod(name = { "copy_data", "copy_data_simple" })
public static IRubyObject copy_data(final ThreadContext context,
IRubyObject fromRuby, IRubyObject toJava) {
JavaArray javaArray = (JavaArray) toJava.dataGetStruct();
RubyArray rubyArray = (RubyArray) fromRuby;

copyDataToJavaArray(rubyArray, javaArray, 0);

return toJava;
}

public static void copyDataToJavaArray(
ThreadContext context, RubyArray rubyArray, JavaArray javaArray) {
int javaLength = (int)javaArray.length().getLongValue();
Class targetType = javaArray.getComponentType();

int rubyLength = rubyArray.getLength();

int i = 0;
for (; i < rubyLength && i < javaLength; i++) {
javaArray.setWithExceptionHandling(i, rubyArray.entry(i).toJava(targetType));

@Deprecated // not used
public static void copyDataToJavaArray(final ThreadContext context,
final RubyArray rubyArray, final JavaArray javaArray) {
copyDataToJavaArray(rubyArray, javaArray, 0);
}

private static void copyDataToJavaArray(
final RubyArray rubyArray, final JavaArray javaArray, int offset) {
int length = javaArray.getLength();
if ( length > rubyArray.getLength() ) length = rubyArray.getLength();

final Class<?> targetType = javaArray.getComponentType();
for ( int i = offset; i < length; i++ ) {
javaArray.setWithExceptionHandling(i, rubyArray.eltInternal(i).toJava(targetType));
}
}

@JRubyMethod
public static IRubyObject dimensions(ThreadContext context, IRubyObject maybeArray) {
Ruby runtime = context.runtime;
if (!(maybeArray instanceof RubyArray)) {
return runtime.newEmptyArray();
}
RubyArray rubyArray = (RubyArray)maybeArray;
RubyArray dims = runtime.newEmptyArray();

return dimsRecurse(context, rubyArray, dims, 0);
public static IRubyObject dimensions(ThreadContext context, IRubyObject rubyArray) {
return dimensions(context, rubyArray, context.runtime.newEmptyArray());
}

@JRubyMethod
public static IRubyObject dimensions(ThreadContext context, IRubyObject maybeArray, IRubyObject dims) {
Ruby runtime = context.runtime;
if (!(maybeArray instanceof RubyArray)) {
public static IRubyObject dimensions(ThreadContext context, IRubyObject rubyArray, IRubyObject dims) {
final Ruby runtime = context.runtime;
if ( ! ( rubyArray instanceof RubyArray ) ) {
return runtime.newEmptyArray();
}
assert dims instanceof RubyArray;

RubyArray rubyArray = (RubyArray)maybeArray;

return dimsRecurse(context, rubyArray, (RubyArray)dims, 0);

return calcDimensions(runtime, (RubyArray) rubyArray, (RubyArray) dims, 0);
}

@JRubyMethod
public static IRubyObject dimensions(ThreadContext context, IRubyObject maybeArray, IRubyObject dims, IRubyObject index) {
Ruby runtime = context.runtime;
if (!(maybeArray instanceof RubyArray)) {
public static IRubyObject dimensions(ThreadContext context, IRubyObject rubyArray, IRubyObject dims, IRubyObject index) {
final Ruby runtime = context.runtime;
if ( ! ( rubyArray instanceof RubyArray ) ) {
return runtime.newEmptyArray();
}
assert dims instanceof RubyArray;
assert index instanceof RubyFixnum;

RubyArray rubyArray = (RubyArray)maybeArray;

return dimsRecurse(context, rubyArray, (RubyArray)dims, (int)((RubyFixnum)index).getLongValue());

final int i = (int) ((RubyFixnum) index).getLongValue();
return calcDimensions(runtime, (RubyArray) rubyArray, (RubyArray) dims, i);
}

private static RubyArray dimsRecurse(ThreadContext context, RubyArray rubyArray, RubyArray dims, int index) {
Ruby runtime = context.runtime;

while (dims.size() <= index) {
dims.append(RubyFixnum.zero(runtime));
private static RubyArray calcDimensions(final Ruby runtime,
final RubyArray array, final RubyArray dims, final int index) {

while ( dims.size() <= index ) {
dims.append( RubyFixnum.zero(runtime) );
}

if (rubyArray.size() > ((RubyFixnum)dims.eltInternal(index)).getLongValue()) {
dims.eltInternalSet(index, RubyFixnum.newFixnum(runtime, rubyArray.size()));

final long dim = ((RubyFixnum) dims.eltInternal(index)).getLongValue();
if ( array.size() > dim ) {
dims.eltInternalSet(index, RubyFixnum.newFixnum(runtime, array.size()));
}

for (int i = 0; i < rubyArray.size(); i++) {
if (rubyArray.eltInternal(i) instanceof RubyArray) {
dimsRecurse(context, (RubyArray)rubyArray.eltInternal(i), dims, 1);

for ( int i = 0; i < array.size(); i++ ) {
final IRubyObject element = array.eltInternal(i);
if ( element instanceof RubyArray ) {
calcDimensions(runtime, (RubyArray) element, dims, 1);
}
}

return dims;
}
}
38 changes: 19 additions & 19 deletions core/src/main/java/org/jruby/java/addons/KernelJavaAddons.java
Original file line number Diff line number Diff line change
@@ -18,28 +18,25 @@

public class KernelJavaAddons {
@JRubyMethod
public static IRubyObject to_java(ThreadContext context, IRubyObject fromObject) {
if (fromObject instanceof RubyArray) {
return context.runtime.getJavaSupport().getObjectJavaClass().javaArrayFromRubyArray(context, fromObject);
} else {
return Java.getInstance(context.runtime, fromObject.toJava(Object.class));
public static IRubyObject to_java(ThreadContext context, final IRubyObject fromObject) {
if ( fromObject instanceof RubyArray ) {
final JavaClass targetType = context.runtime.getJavaSupport().getObjectJavaClass();
return targetType.javaArrayFromRubyArray(context, (RubyArray) fromObject);
}
return Java.getInstance(context.runtime, fromObject.toJava(Object.class));
}

@JRubyMethod
public static IRubyObject to_java(ThreadContext context, IRubyObject fromObject, IRubyObject type) {
if (type.isNil()) {
return to_java(context, fromObject);
}
public static IRubyObject to_java(ThreadContext context, final IRubyObject fromObject, final IRubyObject type) {
if ( type.isNil() ) return to_java(context, fromObject);

Ruby runtime = context.runtime;
JavaClass targetType = getTargetType(context, runtime, type);
final Ruby runtime = context.runtime;
final JavaClass targetType = getTargetType(context, runtime, type);

if (fromObject instanceof RubyArray) {
return targetType.javaArrayFromRubyArray(context, fromObject);
} else {
return Java.getInstance(runtime, fromObject.toJava(targetType.javaClass()));
if ( fromObject instanceof RubyArray ) {
return targetType.javaArrayFromRubyArray(context, (RubyArray) fromObject);
}
return Java.getInstance(runtime, fromObject.toJava(targetType.javaClass()));
}

@JRubyMethod(rest = true)
@@ -90,11 +87,14 @@ private static JavaClass getTargetType(ThreadContext context, Ruby runtime, IRub
if (type instanceof RubyString || type instanceof RubySymbol) {
targetType = runtime.getJavaSupport().getNameClassMap().get(type.asJavaString());
if (targetType == null) targetType = JavaClass.forNameVerbose(runtime, type.asJavaString());
} else if (type instanceof RubyModule && type.respondsTo("java_class")) {
}
else if (type instanceof RubyModule && type.respondsTo("java_class")) {
targetType = (JavaClass) Helpers.invoke(context, type, "java_class");
} else if (type instanceof JavaProxy) {
if (((JavaProxy)type).getObject() instanceof Class) {
targetType = JavaClass.get(runtime, (Class)((JavaProxy)type).getObject());
}
else if (type instanceof JavaProxy) {
final Object wrapped = ((JavaProxy) type).getObject();
if ( wrapped instanceof Class ) {
targetType = JavaClass.get(runtime, (Class) wrapped);
} else {
throw runtime.newTypeError("not a valid target type: " + type);
}
120 changes: 94 additions & 26 deletions core/src/main/java/org/jruby/java/dispatch/CallableSelector.java
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@
import org.jruby.javasupport.JavaUtil;
import org.jruby.javasupport.ParameterTypes;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.CodegenUtils;
import org.jruby.util.collections.IntHashMap;
import static org.jruby.util.CodegenUtils.getBoxType;
import static org.jruby.util.CodegenUtils.prettyParams;

/**
* Method selection logic for calling from Ruby to Java.
@@ -30,7 +32,8 @@ private CallableSelector() { /* no-instances */ }

//private static final boolean DEBUG = true;

public static ParameterTypes matchingCallableArityN(Ruby runtime, Map cache, ParameterTypes[] methods, IRubyObject[] args, int argsLength) {
@SuppressWarnings("unchecked")
public static ParameterTypes matchingCallableArityN(Ruby runtime, Map cache, ParameterTypes[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
ParameterTypes method = (ParameterTypes) cache.get(signatureCode);
if (method == null) {
@@ -43,11 +46,12 @@ public static ParameterTypes matchingCallableArityN(Ruby runtime, Map cache, Par
// NOTE: The five match methods are arity-split to avoid the cost of boxing arguments
// when there's already a cached match. Do not condense them into a single
// method.
public static JavaCallable matchingCallableArityN(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject[] args, int argsLength) {
@SuppressWarnings("unchecked")
public static JavaCallable matchingCallableArityN(Ruby runtime, Map cache, JavaCallable[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = (JavaCallable) findMatchingCallableForArgs(runtime, methods, args);
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) cache.put(signatureCode, method);
}
return method;
@@ -57,7 +61,7 @@ public static JavaCallable matchingCallableArityOne(Ruby runtime, Map cache, Jav
final int signatureCode = argsHashCode(arg0);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = (JavaCallable) findMatchingCallableForArgs(runtime, methods, arg0);
method = findMatchingCallableForArgs(runtime, methods, arg0);
if (method != null) cache.put(signatureCode, method);
}
return method;
@@ -67,7 +71,7 @@ public static JavaCallable matchingCallableArityTwo(Ruby runtime, Map cache, Jav
final int signatureCode = argsHashCode(arg0, arg1);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = (JavaCallable) findMatchingCallableForArgs(runtime, methods, arg0, arg1);
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1);
if (method != null) cache.put(signatureCode, method);
}
return method;
@@ -77,7 +81,7 @@ public static JavaCallable matchingCallableArityThree(Ruby runtime, Map cache, J
final int signatureCode = argsHashCode(arg0, arg1, arg2);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = (JavaCallable) findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
if (method != null) cache.put(signatureCode, method);
}
return method;
@@ -87,30 +91,80 @@ public static JavaCallable matchingCallableArityFour(Ruby runtime, Map cache, Ja
final int signatureCode = argsHashCode(arg0, arg1, arg2, arg3);
JavaCallable method = (JavaCallable) cache.get(signatureCode);
if (method == null) {
method = (JavaCallable) findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

public static <T extends ParameterTypes> T matchingCallableArityN(Ruby runtime, IntHashMap<T> cache, T[] methods, IRubyObject[] args) {
final int signatureCode = argsHashCode(args);
T method = cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, args);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

public static <T extends ParameterTypes> T matchingCallableArityOne(Ruby runtime, IntHashMap<T> cache, T[] methods, IRubyObject arg0) {
final int signatureCode = argsHashCode(arg0);
T method = cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

public static <T extends ParameterTypes> T matchingCallableArityTwo(Ruby runtime, IntHashMap<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1) {
final int signatureCode = argsHashCode(arg0, arg1);
T method = cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

public static <T extends ParameterTypes> T matchingCallableArityThree(Ruby runtime, IntHashMap<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
final int signatureCode = argsHashCode(arg0, arg1, arg2);
T method = cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

public static <T extends ParameterTypes> T matchingCallableArityFour(Ruby runtime, IntHashMap<T> cache, T[] methods, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) {
final int signatureCode = argsHashCode(arg0, arg1, arg2, arg3);
T method = cache.get(signatureCode);
if (method == null) {
method = findMatchingCallableForArgs(runtime, methods, arg0, arg1, arg2, arg3);
if (method != null) cache.put(signatureCode, method);
}
return method;
}

private static ParameterTypes findMatchingCallableForArgs(final Ruby runtime,
final ParameterTypes[] methods, final IRubyObject... args) {
ParameterTypes method = null;
private static <T extends ParameterTypes> T findMatchingCallableForArgs(final Ruby runtime,
final T[] methods, final IRubyObject... args) {
T method = null;

// try the new way first
final List<ParameterTypes> candidates = findCallableCandidates(methods, args);
final List<T> candidates = findCallableCandidates(methods, args);
final int size = candidates.size();

if ( size > 0 ) {
// new way found one, so let's go with that
if ( size == 1 ) method = candidates.get(0);
else { // narrow to most specific version (or first version, if none are more specific)
ParameterTypes mostSpecific = candidates.get(0);
T mostSpecific = candidates.get(0);
Class<?>[] msTypes = mostSpecific.getParameterTypes();
boolean ambiguous = false;

OUTER: for ( int c = 1; c < size; c++ ) {
final ParameterTypes candidate = candidates.get(c);
final T candidate = candidates.get(c);
final Class<?>[] cTypes = candidate.getParameterTypes();

for ( int i = 0; i < msTypes.length; i++ ) {
@@ -126,7 +180,11 @@ private static ParameterTypes findMatchingCallableForArgs(final Ruby runtime,
final Class<?> msType = msTypes[i], cType = cTypes[i];
if ( msType == cType || msType.isAssignableFrom(cType) || cType.isAssignableFrom(msType) ) {
ambiguous = false; continue OUTER;
} else {
}
else if ( cType.isPrimitive() && msType.isAssignableFrom(getBoxType(cType)) ) {
ambiguous = false; continue OUTER;
}
else {
ambiguous = true;
}
}
@@ -147,7 +205,7 @@ private static ParameterTypes findMatchingCallableForArgs(final Ruby runtime,
method = mostSpecific;

if ( ambiguous ) {
runtime.getWarnings().warn("ambiguous Java methods found, using " + ((Member) ((JavaCallable) method).accessibleObject()).getName() + CodegenUtils.prettyParams(msTypes));
runtime.getWarnings().warn("ambiguous Java methods found, using " + ((Member) ((JavaCallable) method).accessibleObject()).getName() + prettyParams(msTypes));
}
}
}
@@ -172,11 +230,11 @@ private static ParameterTypes findMatchingCallableForArgs(final Ruby runtime,
return method;
}

private static ParameterTypes findCallable(ParameterTypes[] callables, CallableAcceptor acceptor, IRubyObject[] args) {
ParameterTypes bestCallable = null;
private static <T extends ParameterTypes> T findCallable(T[] callables, CallableAcceptor acceptor, IRubyObject[] args) {
T bestCallable = null;
int bestScore = -1;
for ( int i = 0; i < callables.length; i++ ) {
ParameterTypes callable = callables[i];
final T callable = callables[i];

if ( acceptor.accept(callable, args) ) {
int currentScore = calcExactnessScore(callable, args);
@@ -188,15 +246,16 @@ private static ParameterTypes findCallable(ParameterTypes[] callables, CallableA
return bestCallable;
}

private static List<ParameterTypes> findCallableCandidates(final ParameterTypes[] callables,
@SuppressWarnings("unchecked")
private static <T extends ParameterTypes> List<T> findCallableCandidates(final T[] callables,
final IRubyObject[] args) {
// in case of an exact match prefer to return it early :
for ( int c = 0; c < callables.length; c++ ) {
final ParameterTypes callable = callables[c];
final T callable = callables[c];
if ( exactMatch(callable, args ) ) return Collections.singletonList(callable);
}

final ArrayList<ParameterTypes> retained = new ArrayList<ParameterTypes>(callables.length);
final ArrayList<T> retained = new ArrayList<T>(callables.length);
ParameterTypes[] incoming = callables.clone();

for ( int i = 0; i < args.length; i++ ) {
@@ -209,7 +268,7 @@ private static List<ParameterTypes> findCallableCandidates(final ParameterTypes[
Class[] types = callable.getParameterTypes();

if ( matcher.match( types[i], args[i] ) ) {
retained.add(callable);
retained.add((T) callable);
incoming[c] = null; // retaining - remove
}
}
@@ -282,7 +341,7 @@ private static interface Matcher {
private static final Matcher EXACT = new Matcher() {
public boolean match(final Class<?> type, final IRubyObject arg) {
final Class<?> argClass = getJavaClass(arg);
return type == argClass || (type.isPrimitive() && CodegenUtils.getBoxType(type) == argClass);
return type == argClass || (type.isPrimitive() && getBoxType(type) == argClass);
}
@Override public String toString() { return "EXACT"; } // for debugging
};
@@ -426,7 +485,7 @@ private static boolean primitivable(final Class<?> type, final IRubyObject arg)
private static int calcTypePreference(Class<?> type, final IRubyObject arg) {
final boolean primitive = type.isPrimitive();

if ( primitive ) type = CodegenUtils.getBoxType(type);
if ( primitive ) type = getBoxType(type);

if ( Number.class.isAssignableFrom(type) || Character.class == type ) {
if ( arg instanceof RubyFixnum ) {
@@ -527,4 +586,13 @@ private static Class<?> getJavaClass(final IRubyObject arg) {
return arg != null ? arg.getJavaClass() : void.class;
}

}
/**
* Internal helper to allocate a callable map to cache argument method matches.
* @param <T> the callable type
* @return cache usable with {@link CallableSelector}
*/
public static <T extends ParameterTypes> IntHashMap<T> newCallableCache() {
return new IntHashMap<T>(8);
}

}
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class ConstructorInvoker extends RubyToJavaInvoker {
public final class ConstructorInvoker extends RubyToJavaInvoker {

public ConstructorInvoker(RubyModule host, List<Constructor> ctors) {
super(host, ctors.toArray(new Constructor[ctors.size()]));
@@ -59,12 +59,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
final Object[] convertedArgs;
JavaConstructor constructor = (JavaConstructor) findCallable(self, name, args, len);
if (constructor.isVarArgs()) {
len = constructor.getParameterTypes().length - 1;
len = constructor.getArity() - 1;
convertedArgs = new Object[len + 1];
for (int i = 0; i < len && i < args.length; i++) {
convertedArgs[i] = convertArg(args[i], constructor, i);
}
convertedArgs[len] = convertVarargs(args, constructor);
convertedArgs[len] = convertVarArgs(args, constructor);
} else {
convertedArgs = new Object[len];
for (int i = 0; i < len && i < args.length; i++) {
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class InstanceMethodInvoker extends MethodInvoker {
public final class InstanceMethodInvoker extends MethodInvoker {
public InstanceMethodInvoker(RubyModule host, List<Method> methods) {
super(host, methods);
}
@@ -28,12 +28,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
final Object[] convertedArgs;
JavaMethod method = (JavaMethod)findCallable(self, name, args, len);
if (method.isVarArgs()) {
len = method.getParameterTypes().length - 1;
len = method.getArity() - 1;
convertedArgs = new Object[len + 1];
for (int i = 0; i < len && i < args.length; i++) {
convertedArgs[i] = convertArg(args[i], method, i);
}
convertedArgs[len] = convertVarargs(args, method);
convertedArgs[len] = convertVarArgs(args, method);
} else {
convertedArgs = new Object[len];
for (int i = 0; i < len && i < args.length; i++) {
352 changes: 193 additions & 159 deletions core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -11,17 +11,18 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class SingletonMethodInvoker extends MethodInvoker {
private Object singleton;
public final class SingletonMethodInvoker extends MethodInvoker {

private final Object singleton;

public SingletonMethodInvoker(Object singleton, RubyClass host, List<Method> methods) {
super(host, methods);
this.singleton = singleton;
this.singleton = singleton;
}

public SingletonMethodInvoker(Object singleton, RubyClass host, Method method) {
super(host, method);
this.singleton = singleton;
this.singleton = singleton;
}

@Override
@@ -30,12 +31,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
final Object[] convertedArgs;
JavaMethod method = (JavaMethod)findCallable(self, name, args, len);
if (method.isVarArgs()) {
len = method.getParameterTypes().length - 1;
len = method.getArity() - 1;
convertedArgs = new Object[len + 1];
for (int i = 0; i < len && i < args.length; i++) {
convertedArgs[i] = convertArg(args[i], method, i);
}
convertedArgs[len] = convertVarargs(args, method);
convertedArgs[len] = convertVarArgs(args, method);
} else {
convertedArgs = new Object[len];
for (int i = 0; i < len && i < args.length; i++) {
24 changes: 10 additions & 14 deletions core/src/main/java/org/jruby/java/invokers/StaticMethodInvoker.java
Original file line number Diff line number Diff line change
@@ -11,8 +11,8 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class StaticMethodInvoker extends MethodInvoker {
public final class StaticMethodInvoker extends MethodInvoker {

public StaticMethodInvoker(RubyClass host, List<Method> methods) {
super(host, methods);
}
@@ -27,12 +27,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
final Object[] convertedArgs;
JavaMethod method = (JavaMethod)findCallable(self, name, args, len);
if (method.isVarArgs()) {
len = method.getParameterTypes().length - 1;
len = method.getArity() - 1;
convertedArgs = new Object[len + 1];
for (int i = 0; i < len && i < args.length; i++) {
convertedArgs[i] = convertArg(args[i], method, i);
}
convertedArgs[len] = convertVarargs(args, method);
convertedArgs[len] = convertVarArgs(args, method);
} else {
convertedArgs = new Object[len];
for (int i = 0; i < len && i < args.length; i++) {
@@ -96,9 +96,8 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
}

return method.invokeStaticDirect(context, convertedArgs);
} else {
return call(context, self, clazz, name, args);
}
return call(context, self, clazz, name, args);
}

@Override
@@ -109,9 +108,8 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
Object cArg0 = convertArg(proc, method, 0);

return method.invokeStaticDirect(context, cArg0);
} else {
return call(context, self, clazz, name);
}
return call(context, self, clazz, name);
}

@Override
@@ -123,9 +121,8 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
Object cArg1 = convertArg(proc, method, 1);

return method.invokeStaticDirect(context, cArg0, cArg1);
} else {
return call(context, self, clazz, name, arg0);
}
return call(context, self, clazz, name, arg0);
}

@Override
@@ -138,9 +135,9 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
Object cArg2 = convertArg(proc, method, 2);

return method.invokeStaticDirect(context, cArg0, cArg1, cArg2);
} else {
return call(context, self, clazz, name, arg0, arg1);

}
return call(context, self, clazz, name, arg0, arg1);
}

@Override
@@ -154,8 +151,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
Object cArg3 = convertArg(proc, method, 3);

return method.invokeStaticDirect(context, cArg0, cArg1, cArg2, cArg3);
} else {
return call(context, self, clazz, name, arg0, arg1, arg2);
}
return call(context, self, clazz, name, arg0, arg1, arg2);
}
}
37 changes: 29 additions & 8 deletions core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java
Original file line number Diff line number Diff line change
@@ -10,10 +10,13 @@
import org.jruby.RubyInteger;
import org.jruby.RubyModule;
import org.jruby.RubyRange;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.java.util.ArrayUtils;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaArray;
import org.jruby.javasupport.JavaClass;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
@@ -25,12 +28,12 @@ public class ArrayJavaProxy extends JavaProxy {

private final JavaUtil.JavaConverter converter;

public ArrayJavaProxy(Ruby runtime, RubyClass klazz, Object ary) {
this(runtime, klazz, ary, JavaUtil.getJavaConverter(ary.getClass().getComponentType()));
public ArrayJavaProxy(Ruby runtime, RubyClass klazz, Object array) {
this(runtime, klazz, array, JavaUtil.getJavaConverter(array.getClass().getComponentType()));
}

public ArrayJavaProxy(Ruby runtime, RubyClass klazz, Object ary, JavaUtil.JavaConverter converter) {
super(runtime, klazz, ary);
public ArrayJavaProxy(Ruby runtime, RubyClass klazz, Object array, JavaUtil.JavaConverter converter) {
super(runtime, klazz, array);
this.converter = converter;
}

@@ -50,6 +53,17 @@ public static RubyClass createArrayJavaProxy(ThreadContext context) {
return arrayJavaProxy;
}

static ArrayJavaProxy newArray(final Ruby runtime, final Class<?> elementType, final int... dimensions) {
final Object array;
try {
array = Array.newInstance(elementType, dimensions);
}
catch (IllegalArgumentException e) {
throw runtime.newArgumentError("can not create " + dimensions.length + " dimensional array");
}
return new ArrayJavaProxy(runtime, Java.getProxyClassForObject(runtime, array), array);
}

public JavaArray getJavaArray() {
JavaArray javaArray = (JavaArray) dataGetStruct();

@@ -62,12 +76,12 @@ public JavaArray getJavaArray() {
}

@JRubyMethod(name = {"length", "size"})
public IRubyObject length(ThreadContext context) {
public RubyFixnum length(ThreadContext context) {
return context.runtime.newFixnum( Array.getLength( getObject() ) );
}

@JRubyMethod(name = "empty?")
public IRubyObject empty(ThreadContext context) {
public RubyBoolean empty_p(ThreadContext context) {
return context.runtime.newBoolean( Array.getLength( getObject() ) == 0 );
}

@@ -148,8 +162,15 @@ public RubyArray to_a(ThreadContext context) {
return JavaUtil.convertJavaArrayToRubyWithNesting(context, array);
}

@JRubyMethod(name = {"component_type"})
public IRubyObject component_type(ThreadContext context) {
Class<?> componentType = getObject().getClass().getComponentType();
final JavaClass javaClass = JavaClass.get(context.runtime, componentType);
return Java.getProxyClass(context.runtime, javaClass);
}

@JRubyMethod
public IRubyObject inspect(ThreadContext context) {
public RubyString inspect(ThreadContext context) {
final StringBuilder buffer = new StringBuilder();
Class<?> componentClass = getObject().getClass().getComponentType();

@@ -184,7 +205,7 @@ public IRubyObject inspect(ThreadContext context) {
buffer.append(Arrays.toString((Object[]) getObject()));
}
buffer.append('@').append(Integer.toHexString(inspectHashCode()));
return context.runtime.newString(buffer.toString());
return RubyString.newString(context.runtime, buffer.toString());
}

@JRubyMethod(name = "==")
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.jruby.java.proxies;

import java.lang.reflect.Array;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyObject;
import org.jruby.anno.JRubyMethod;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
@@ -27,7 +26,8 @@
*/
public class ArrayJavaProxyCreator extends RubyObject {
private static final int[] EMPTY = new int[0];
Class elementClass;

/* final */ Class<?> elementType;
int[] dimensions = EMPTY;

public static RubyClass createArrayJavaProxyCreator(ThreadContext context) {
@@ -37,37 +37,47 @@ public static RubyClass createArrayJavaProxyCreator(ThreadContext context) {
return arrayJavaProxyCreator;
}

public ArrayJavaProxyCreator(Ruby runtime) {
@Deprecated
public ArrayJavaProxyCreator(final Ruby runtime) {
super(runtime, runtime.getJavaSupport().getArrayJavaProxyCreatorClass());
}

ArrayJavaProxyCreator(final ThreadContext context, JavaClass elementType, final IRubyObject[] sizes) {
this(context.runtime);
this.elementType = elementType.javaClass();
assert sizes.length > 0;
aggregateDimensions(sizes);
}

@Deprecated // no longer used
public void setup(ThreadContext context, IRubyObject javaClass, IRubyObject[] sizes) {
elementClass = (Class) javaClass.toJava(Class.class);
elementType = (Class) javaClass.toJava(Class.class);
aggregateDimensions(sizes);
}

@JRubyMethod(required = 1, rest = true)
@JRubyMethod(name = "[]", required = 1, rest = true)
public IRubyObject op_aref(ThreadContext context, IRubyObject[] sizes) {
Arity.checkArgumentCount(context.runtime, sizes, 1, -1);
aggregateDimensions(sizes);
return this;
}

@JRubyMethod(name = "new")
public IRubyObject _new(ThreadContext context) {
Ruby runtime = context.runtime;
Object array = Array.newInstance(elementClass, dimensions);

return new ArrayJavaProxy(runtime, Java.getProxyClassForObject(runtime, array), array);
@JRubyMethod(name = { "new", "new_instance" })
public final ArrayJavaProxy new_instance(ThreadContext context) {
return ArrayJavaProxy.newArray(context.runtime, elementType, dimensions);
}

private void aggregateDimensions(IRubyObject[] sizes) {
int[] newDimensions = new int[dimensions.length + sizes.length];
System.arraycopy(dimensions, 0, newDimensions, 0, dimensions.length);
for (int i = 0; i < sizes.length; i++) {
IRubyObject size = sizes[i];
int intSize = (int) size.convertToInteger().getLongValue();
newDimensions[i + dimensions.length] = intSize;
private void aggregateDimensions(final IRubyObject[] sizes) {
final int slen = sizes.length; if ( slen == 0 ) return;
final int dlen = dimensions.length;
final int[] newDimensions = new int[ dlen + slen ];
if ( dlen == 1 ) newDimensions[0] = dimensions[0];
else {
System.arraycopy(dimensions, 0, newDimensions, 0, dlen);
}
for ( int i = 0; i < slen; i++ ) {
int size = (int) sizes[i].convertToInteger().getLongValue();
newDimensions[ i + dlen ] = size;
}
dimensions = newDimensions;
}
386 changes: 235 additions & 151 deletions core/src/main/java/org/jruby/java/proxies/JavaInterfaceTemplate.java

Large diffs are not rendered by default.

37 changes: 19 additions & 18 deletions core/src/main/java/org/jruby/java/proxies/JavaProxy.java
Original file line number Diff line number Diff line change
@@ -122,6 +122,10 @@ public Class getJavaClass() {
return getObject().getClass();
}

static JavaClass java_class(final ThreadContext context, final RubyModule module) {
return (JavaClass) Helpers.invoke(context, module, "java_class");
}

@JRubyMethod(meta = true, frame = true) // framed for invokeSuper
public static IRubyObject inherited(ThreadContext context, IRubyObject recv, IRubyObject subclass) {
IRubyObject subJavaClass = Helpers.invoke(context, subclass, "java_class");
@@ -139,23 +143,19 @@ public static RubyClass singleton_class(final IRubyObject self) {

@JRubyMethod(name = "[]", meta = true, rest = true)
public static IRubyObject op_aref(ThreadContext context, IRubyObject self, IRubyObject[] args) {
IRubyObject javaClass = Helpers.invoke(context, self, "java_class");
final JavaClass javaClass = java_class(context, (RubyModule) self);
if ( args.length > 0 ) { // construct new array proxy (ArrayJavaProxy)
ArrayJavaProxyCreator arrayProxyCreator = new ArrayJavaProxyCreator(context.runtime);
arrayProxyCreator.setup(context, javaClass, args);
return arrayProxyCreator;
return new ArrayJavaProxyCreator(context, javaClass, args); // e.g. Byte[64]
}
return Java.get_proxy_class(javaClass, Helpers.invoke(context, javaClass, "array_class"));
}

@JRubyMethod(meta = true)
public static IRubyObject new_array(ThreadContext context, IRubyObject recv, IRubyObject arg0) {
JavaClass javaClass = (JavaClass) Helpers.invoke(context, recv, "java_class");
RubyClass proxyClass = (RubyClass)recv;
Class componentType = javaClass.javaClass();

// construct new array proxy (ArrayJavaProxy)
return new ArrayJavaProxy(context.runtime, proxyClass, Array.newInstance(componentType, (int) arg0.convertToInteger().getLongValue()));
public static IRubyObject new_array(ThreadContext context, IRubyObject self, IRubyObject len) {
final JavaClass javaClass = java_class(context, (RubyModule) self);
final Class<?> componentType = javaClass.javaClass();
final int length = (int) len.convertToInteger().getLongValue();
return ArrayJavaProxy.newArray(context.runtime, componentType, length);
}

@JRubyMethod(name = "__persistent__=", meta = true)
@@ -442,9 +442,9 @@ private MethodInvoker getMethodInvoker(Method method) {
private RubyMethod getRubyMethod(ThreadContext context, String name, Class... argTypes) {
Method jmethod = getMethod(context, name, argTypes);
if (Modifier.isStatic(jmethod.getModifiers())) {
return RubyMethod.newMethod(metaClass.getSingletonClass(), CodegenUtils.prettyParams(argTypes), metaClass.getSingletonClass(), name, getMethodInvoker(jmethod), getMetaClass());
return RubyMethod.newMethod(metaClass.getSingletonClass(), CodegenUtils.prettyParams(argTypes).toString(), metaClass.getSingletonClass(), name, getMethodInvoker(jmethod), getMetaClass());
} else {
return RubyMethod.newMethod(metaClass, CodegenUtils.prettyParams(argTypes), metaClass, name, getMethodInvoker(jmethod), this);
return RubyMethod.newMethod(metaClass, CodegenUtils.prettyParams(argTypes).toString(), metaClass, name, getMethodInvoker(jmethod), this);
}
}

@@ -486,14 +486,15 @@ public RubyClass getSingletonClass() {
}

private void confirmCachedProxy(String message) {
RubyClass realClass = metaClass.getRealClass();
if (!realClass.getCacheProxy()) {
final RubyClass realClass = metaClass.getRealClass();
if ( ! realClass.getCacheProxy() ) {
final Ruby runtime = getRuntime();
if (Java.OBJECT_PROXY_CACHE) {
getRuntime().getWarnings().warnOnce(IRubyWarnings.ID.NON_PERSISTENT_JAVA_PROXY, MessageFormat.format(message, realClass));
runtime.getWarnings().warnOnce(IRubyWarnings.ID.NON_PERSISTENT_JAVA_PROXY, MessageFormat.format(message, realClass));
} else {
getRuntime().getWarnings().warn(MessageFormat.format(message, realClass));
runtime.getWarnings().warn(MessageFormat.format(message, realClass));
realClass.setCacheProxy(true);
getRuntime().getJavaSupport().getObjectProxyCache().put(getObject(), this);
runtime.getJavaSupport().getObjectProxyCache().put(getObject(), this);
}
}
}
104 changes: 71 additions & 33 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -67,6 +67,7 @@
import org.jruby.RubyMethod;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyProc;
import org.jruby.RubyString;
import org.jruby.RubyUnboundMethod;
import org.jruby.javasupport.binding.Initializer;
@@ -82,6 +83,7 @@
import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.JavaMethod.JavaMethodN;
import org.jruby.internal.runtime.methods.JavaMethod.JavaMethodZero;
import org.jruby.java.addons.ArrayJavaAddons;
@@ -107,6 +109,8 @@
import org.jruby.util.CodegenUtils;
import org.jruby.util.IdUtil;
import org.jruby.util.cli.Options;
import org.jruby.util.collections.IntHashMap;
import static org.jruby.java.dispatch.CallableSelector.newCallableCache;

@JRubyModule(name = "Java")
public class Java implements Library {
@@ -167,7 +171,7 @@ public static RubyModule createJavaModule(final Ruby runtime) {
MapJavaProxy.createMapJavaProxy(runtime);

// also create the JavaProxy* classes
JavaProxyClass.createJavaProxyModule(runtime);
JavaProxyClass.createJavaProxyClasses(runtime, Java);

// The template for interface modules
JavaInterfaceTemplate.createJavaInterfaceTemplateModule(context);
@@ -222,53 +226,45 @@ public static IRubyObject inherited(IRubyObject self, IRubyObject arg0) {
* @param nameClassMap
*/
private static void addNameClassMappings(final Ruby runtime, final Map<String, JavaClass> nameClassMap) {
JavaClass booleanPrimClass = JavaClass.get(runtime, Boolean.TYPE);
JavaClass booleanClass = JavaClass.get(runtime, Boolean.class);
nameClassMap.put("boolean", booleanPrimClass);
nameClassMap.put("boolean", JavaClass.get(runtime, Boolean.TYPE));
nameClassMap.put("Boolean", booleanClass);
nameClassMap.put("java.lang.Boolean", booleanClass);

JavaClass bytePrimClass = JavaClass.get(runtime, Byte.TYPE);
JavaClass byteClass = JavaClass.get(runtime, Byte.class);
nameClassMap.put("byte", bytePrimClass);
nameClassMap.put("byte", JavaClass.get(runtime, Byte.TYPE));
nameClassMap.put("Byte", byteClass);
nameClassMap.put("java.lang.Byte", byteClass);

JavaClass shortPrimClass = JavaClass.get(runtime, Short.TYPE);
JavaClass shortClass = JavaClass.get(runtime, Short.class);
nameClassMap.put("short", shortPrimClass);
nameClassMap.put("short", JavaClass.get(runtime, Short.TYPE));
nameClassMap.put("Short", shortClass);
nameClassMap.put("java.lang.Short", shortClass);

JavaClass charPrimClass = JavaClass.get(runtime, Character.TYPE);
JavaClass charClass = JavaClass.get(runtime, Character.class);
nameClassMap.put("char", charPrimClass);
nameClassMap.put("char", JavaClass.get(runtime, Character.TYPE));
nameClassMap.put("Character", charClass);
nameClassMap.put("Char", charClass);
nameClassMap.put("java.lang.Character", charClass);

JavaClass intPrimClass = JavaClass.get(runtime, Integer.TYPE);
JavaClass intClass = JavaClass.get(runtime, Integer.class);
nameClassMap.put("int", intPrimClass);
nameClassMap.put("int", JavaClass.get(runtime, Integer.TYPE));
nameClassMap.put("Integer", intClass);
nameClassMap.put("Int", intClass);
nameClassMap.put("java.lang.Integer", intClass);

JavaClass longPrimClass = JavaClass.get(runtime, Long.TYPE);
JavaClass longClass = JavaClass.get(runtime, Long.class);
nameClassMap.put("long", longPrimClass);
nameClassMap.put("long", JavaClass.get(runtime, Long.TYPE));
nameClassMap.put("Long", longClass);
nameClassMap.put("java.lang.Long", longClass);

JavaClass floatPrimClass = JavaClass.get(runtime, Float.TYPE);
JavaClass floatClass = JavaClass.get(runtime, Float.class);
nameClassMap.put("float", floatPrimClass);
nameClassMap.put("float", JavaClass.get(runtime, Float.TYPE));
nameClassMap.put("Float", floatClass);
nameClassMap.put("java.lang.Float", floatClass);

JavaClass doublePrimClass = JavaClass.get(runtime, Double.TYPE);
JavaClass doubleClass = JavaClass.get(runtime, Double.class);
nameClassMap.put("double", doublePrimClass);
nameClassMap.put("double", JavaClass.get(runtime, Double.TYPE));
nameClassMap.put("Double", doubleClass);
nameClassMap.put("java.lang.Double", doubleClass);

@@ -292,6 +288,9 @@ private static void addNameClassMappings(final Ruby runtime, final Map<String, J
nameClassMap.put("string", stringClass);
nameClassMap.put("String", stringClass);
nameClassMap.put("java.lang.String", stringClass);

nameClassMap.put("void", JavaClass.get(runtime, Void.TYPE));
nameClassMap.put("Void", JavaClass.get(runtime, Void.class));
}

private static class JavaPackageClassProvider implements ClassProvider {
@@ -416,17 +415,17 @@ else if ( javaClassObject instanceof JavaClass ) {
return getInterfaceModule(runtime, javaClass);
}

public static RubyModule get_proxy_class(final IRubyObject self, final IRubyObject java_class_object) {
public static RubyModule get_proxy_class(final IRubyObject self, final IRubyObject java_class) {
final Ruby runtime = self.getRuntime();
final JavaClass javaClass;
if ( java_class_object instanceof RubyString ) {
javaClass = JavaClass.for_name(self, java_class_object);
if ( java_class instanceof RubyString ) {
javaClass = JavaClass.for_name(self, java_class);
}
else if ( java_class_object instanceof JavaClass ) {
javaClass = (JavaClass) java_class_object;
else if ( java_class instanceof JavaClass ) {
javaClass = (JavaClass) java_class;
}
else {
throw runtime.newTypeError(java_class_object, runtime.getJavaSupport().getJavaClassClass());
throw runtime.newTypeError(java_class, runtime.getJavaSupport().getJavaClassClass());
}
return getProxyClass(runtime, javaClass);
}
@@ -745,7 +744,9 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
});

subclass.addMethod("__jcreate!", new JavaMethodN(subclassSingleton, PUBLIC) {
private final Map<Integer, ParameterTypes> methodCache = new HashMap<Integer, ParameterTypes>();

private final IntHashMap<JavaProxyConstructor> cache = newCallableCache();

@Override
public IRubyObject call(final ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
IRubyObject proxyClass = self.getMetaClass().getInstanceVariables().getInstanceVariable("@java_proxy_class");
@@ -759,18 +760,19 @@ public IRubyObject call(final ThreadContext context, IRubyObject self, RubyModul
ArrayList<JavaProxyConstructor> forArity = new ArrayList<JavaProxyConstructor>(constructors.size());
for ( int i = 0; i < constructors.size(); i++ ) {
JavaProxyConstructor constructor = (JavaProxyConstructor) constructors.eltInternal(i);
if ( constructor.getParameterTypes().length == argsLength ) forArity.add(constructor);
if ( constructor.getArity() == argsLength ) forArity.add(constructor);
}

if ( forArity.size() == 0 ) {
throw context.runtime.newArgumentError("wrong number of arguments for constructor");
}

JavaProxyConstructor matching = (JavaProxyConstructor)CallableSelector.matchingCallableArityN(
context.runtime, methodCache,
forArity.toArray(new JavaProxyConstructor[forArity.size()]), args, args.length);
final JavaProxyConstructor matching = CallableSelector.matchingCallableArityN(
context.runtime, cache,
forArity.toArray(new JavaProxyConstructor[forArity.size()]), args
);

if (matching == null) {
if ( matching == null ) {
throw context.runtime.newArgumentError("wrong number of arguments for constructor");
}

@@ -944,8 +946,13 @@ private static RubyModule getProxyOrPackageUnderPackage(final ThreadContext cont
// we'll try as a package
result = getJavaPackageModule(runtime, fullName);
// NOTE result = getPackageModule(runtime, name);
if ( result == null ) {
throw runtime.newNameError("missing class (or package) name (`" + fullName + "')", fullName);
}
}
else {
throw runtime.newNameError("missing class name (`" + fullName + "')", fullName);
}
throw runtime.newNameError("missing class name (`" + fullName + "')", fullName);
}
}
catch (RuntimeException e) {
@@ -1089,13 +1096,44 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
}

@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
return this.packageOrClass;
}

@Override
public Arity getArity() {
return Arity.noArguments();
public final IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
return this.packageOrClass;
}

@Override
public Arity getArity() { return Arity.noArguments(); }

}

final static class ProcToInterface extends org.jruby.internal.runtime.methods.DynamicMethod {

ProcToInterface(final RubyClass singletonClass) {
super(singletonClass, PUBLIC, org.jruby.internal.runtime.methods.CallConfiguration.FrameNoneScopeNone);
}

@Override // method_missing impl :
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
if ( ! ( self instanceof RubyProc ) ) {
throw context.runtime.newTypeError("interface impl method_missing for block used with non-Proc object");
}
final RubyProc proc = (RubyProc) self;
final IRubyObject[] newArgs;
if ( args.length == 1 ) newArgs = IRubyObject.NULL_ARRAY;
else {
newArgs = new IRubyObject[ args.length - 1 ];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
}
return proc.call(context, newArgs);
}

@Override
public DynamicMethod dup() {
return this;
}

}
40 changes: 18 additions & 22 deletions core/src/main/java/org/jruby/javasupport/JavaArrayUtilities.java
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
* rights and limitations under the License.
*
* Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -51,44 +51,40 @@ public static RubyModule createJavaArrayUtilitiesModule(Ruby runtime) {
javaArrayUtils.defineAnnotatedMethods(JavaArrayUtilities.class);
return javaArrayUtils;
}

@JRubyMethod(module = true, visibility = Visibility.PRIVATE)
public static IRubyObject bytes_to_ruby_string(ThreadContext context, IRubyObject recv, IRubyObject wrappedObject) {
return bytes_to_ruby_string(context, recv, wrappedObject, context.nil);
}

@JRubyMethod(module = true, visibility = Visibility.PRIVATE)
public static IRubyObject bytes_to_ruby_string(ThreadContext context, IRubyObject recv, IRubyObject wrappedObject, IRubyObject encoding) {
Ruby runtime = recv.getRuntime();
byte[] bytes = null;

if (wrappedObject instanceof JavaProxy) {
Object wrapped = ((JavaProxy)wrappedObject).getObject();
if (wrapped instanceof byte[]) {
bytes = (byte[])wrapped;
}
Object wrapped = ((JavaProxy) wrappedObject).getObject();
if ( wrapped instanceof byte[] ) bytes = (byte[]) wrapped;
} else {
IRubyObject byteArray = (IRubyObject)wrappedObject.dataGetStruct();
if (byteArray instanceof JavaArray &&
((JavaArray)byteArray).getValue() instanceof byte[]) {
bytes = (byte[])((JavaArray)byteArray).getValue();
IRubyObject byteArray = (IRubyObject) wrappedObject.dataGetStruct();
if (byteArray instanceof JavaArray) {
final Object wrapped = ((JavaArray) byteArray).getValue();
if ( wrapped instanceof byte[] ) bytes = (byte[]) wrapped;
}
}

if (bytes == null) {
throw runtime.newTypeError("wrong argument type " + wrappedObject.getMetaClass() +
" (expected byte[])");
throw context.runtime.newTypeError("wrong argument type " +
wrappedObject.getMetaClass() + " (expected byte[])"
);
}

RubyString string = runtime.newString(new ByteList(bytes, true));

if (!encoding.isNil()) {
string.force_encoding(context, encoding);
}

RubyString string = context.runtime.newString(new ByteList(bytes, true));

if ( ! encoding.isNil() ) string.force_encoding(context, encoding);

return string;
}

@JRubyMethod(module = true, visibility = Visibility.PRIVATE)
public static IRubyObject ruby_string_to_bytes(IRubyObject recv, IRubyObject string) {
Ruby runtime = recv.getRuntime();
47 changes: 25 additions & 22 deletions core/src/main/java/org/jruby/javasupport/JavaCallable.java
Original file line number Diff line number Diff line change
@@ -126,26 +126,6 @@ public RubyString to_generic_string() {
return getRuntime().newString(toGenericString());
}

@JRubyMethod
public RubyString inspect() {
StringBuilder str = new StringBuilder();
str.append( nameOnInspection() );
dumpParameterTypes(str, false);
str.append(")>");
return getRuntime().newString( str.toString() );
}

private CharSequence dumpParameterTypes(final StringBuilder str, final boolean brackets) {
if ( brackets ) str.append('[');
final Class<?>[] types = parameterTypes;
for ( int i = 0; i < types.length; i++ ) {
str.append( types[i].getName() );
if ( i < types.length - 1 ) str.append(',');
}
if ( brackets ) str.append(']');
return str;
}

@JRubyMethod(name = "public?")
public RubyBoolean public_p() {
return RubyBoolean.newBoolean(getRuntime(), Modifier.isPublic(getModifiers()));
@@ -195,7 +175,7 @@ final IRubyObject handlelIllegalArgumentEx(final IllegalArgumentException ex, Me
final StringBuilder msg = new StringBuilder(64);
msg.append("for method ").append( target.getDeclaringClass().getSimpleName() )
.append('.').append( target.getName() );
msg.append(" expected "); dumpParameterTypes(msg, true);
msg.append(" expected "); dumpParameterTypes(msg);
msg.append("; got: "); dumpArgTypes(arguments, msg);
msg.append("; error: ").append( ex.getMessage() );
throw getRuntime().newTypeError( msg.toString() );
@@ -210,12 +190,18 @@ final IRubyObject handlelIllegalArgumentEx(final IllegalArgumentException ex, Co
if ( targetInfo ) {
msg.append("for constructor of type ").append( target.getDeclaringClass().getSimpleName() );
}
msg.append(" expected "); dumpParameterTypes(msg, true);
msg.append(" expected "); dumpParameterTypes(msg);
msg.append("; got: "); dumpArgTypes(arguments, msg);
msg.append("; error: ").append( ex.getMessage() );
throw getRuntime().newTypeError( msg.toString() );
}

private void dumpParameterTypes(final StringBuilder str) {
str.append('[');
inspectParameterTypes(str, this, false);
str.append(']');
}

static CharSequence dumpArgTypes(final Object[] args, final StringBuilder str) {
str.append('[');
for ( int i = 0; i < args.length; i++ ) {
@@ -227,4 +213,21 @@ static CharSequence dumpArgTypes(final Object[] args, final StringBuilder str) {
return str;
}

public static StringBuilder inspectParameterTypes(
final StringBuilder str, final ParameterTypes target) {
return inspectParameterTypes(str, target, true);
}

private static StringBuilder inspectParameterTypes(
final StringBuilder str, final ParameterTypes target, final boolean brackets) {
if ( brackets ) str.append('(');
final Class<?>[] types = target.getParameterTypes();
for ( int i = 0; i < types.length; i++ ) {
str.append( types[i].getName() );
if ( i < types.length - 1 ) str.append(',');
}
if ( brackets ) str.append(')');
return str;
}

}
186 changes: 100 additions & 86 deletions core/src/main/java/org/jruby/javasupport/JavaClass.java
Original file line number Diff line number Diff line change
@@ -69,6 +69,8 @@
@JRubyClass(name="Java::JavaClass", parent="Java::JavaObject")
public class JavaClass extends JavaObject {

public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];

public JavaClass(final Ruby runtime, final Class<?> javaClass) {
super(runtime, runtime.getJavaSupport().getJavaClassClass(), javaClass);
}
@@ -123,7 +125,7 @@ public static RubyArray getRubyArray(Ruby runtime, Class<?>[] classes) {
return toRubyArray(runtime, classes);
}

static RubyArray toRubyArray(final Ruby runtime, final Class<?>[] classes) {
public static RubyArray toRubyArray(final Ruby runtime, final Class<?>[] classes) {
IRubyObject[] javaClasses = new IRubyObject[classes.length];
for ( int i = classes.length; --i >= 0; ) {
javaClasses[i] = get(runtime, classes[i]);
@@ -507,99 +509,100 @@ else if (other instanceof ConcreteJavaProxy) {

@JRubyMethod
public RubyArray java_instance_methods() {
return java_methods(javaClass().getMethods(), false);
return toJavaMethods(javaClass().getMethods(), false);
}

@JRubyMethod
public RubyArray declared_instance_methods() {
return java_methods(javaClass().getDeclaredMethods(), false);
return toJavaMethods(javaClass().getDeclaredMethods(), false);
}

@JRubyMethod
public RubyArray java_class_methods() {
return toJavaMethods(javaClass().getMethods(), true);
}

@JRubyMethod
public RubyArray declared_class_methods() {
return toJavaMethods(javaClass().getDeclaredMethods(), true);
}

private RubyArray java_methods(final Method[] methods, final boolean isStatic) {
private RubyArray toJavaMethods(final Method[] methods, final boolean isStatic) {
final Ruby runtime = getRuntime();
final RubyArray result = runtime.newArray(methods.length);
for ( int i = 0; i < methods.length; i++ ) {
final Method method = methods[i];
if ( isStatic == Modifier.isStatic(method.getModifiers()) ) {
result.append( JavaMethod.create(runtime, method) );
result.append( new JavaMethod(runtime, method) );
}
}
return result;
}

@JRubyMethod
public RubyArray java_class_methods() {
return java_methods(javaClass().getMethods(), true);
}

@JRubyMethod
public RubyArray declared_class_methods() {
return java_methods(javaClass().getDeclaredMethods(), true);
}

@JRubyMethod(required = 1, rest = true)
public JavaMethod java_method(IRubyObject[] args) {
final Ruby runtime = getRuntime();
if ( args.length < 1 ) throw runtime.newArgumentError(args.length, 1);

final String methodName = args[0].asJavaString();
try {
Class<?>[] argumentTypes = buildArgumentTypes(runtime, args);
return JavaMethod.create(runtime, javaClass(), methodName, argumentTypes);
Class<?>[] argumentTypes = getArgumentTypes(runtime, args, 1);
@SuppressWarnings("unchecked")
final Method method = javaClass().getMethod(methodName, argumentTypes);
return new JavaMethod(runtime, method);
}
catch (ClassNotFoundException cnfe) {
throw runtime.newNameError("undefined method '" + methodName +
"' for class '" + javaClass().getName() + "'", methodName);
catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass().getName() + "'", methodName);
}

}

@JRubyMethod(required = 1, rest = true)
public JavaMethod declared_method(final IRubyObject[] args) {
final Ruby runtime = getRuntime();
if ( args.length < 1 ) throw runtime.newArgumentError(args.length, 1);

final String methodName = args[0].asJavaString();
try {
Class<?>[] argumentTypes = buildArgumentTypes(runtime, args);
return JavaMethod.createDeclared(runtime, javaClass(), methodName, argumentTypes);
Class<?>[] argumentTypes = getArgumentTypes(runtime, args, 1);
@SuppressWarnings("unchecked")
final Method method = javaClass().getDeclaredMethod(methodName, argumentTypes);
return new JavaMethod(runtime, method);
}
catch (ClassNotFoundException cnfe) {
throw runtime.newNameError("undefined method '" + methodName +
"' for class '" + javaClass().getName() + "'", methodName);
catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass().getName() + "'", methodName);
}
}

@JRubyMethod(required = 1, rest = true)
public JavaCallable declared_method_smart(final IRubyObject[] args) {
final Ruby runtime = getRuntime();
if ( args.length < 1 ) throw runtime.newArgumentError(args.length, 1);

final String methodName = args[0].asJavaString();
try {
Class<?>[] argumentTypes = buildArgumentTypes(runtime, args);

JavaCallable callable = getMatchingCallable(runtime, javaClass(), methodName, argumentTypes);
Class<?>[] argumentTypes = getArgumentTypes(runtime, args, 1);

if ( callable != null ) return callable;
}
catch (ClassNotFoundException cnfe) {
/* fall through to error below */
}
JavaCallable callable = getMatchingCallable(runtime, javaClass(), methodName, argumentTypes);

if ( callable != null ) return callable;

throw runtime.newNameError("undefined method '" + methodName +
"' for class '" + javaClass().getName() + "'", methodName);
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass().getName() + "'", methodName);
}

public static JavaCallable getMatchingCallable(Ruby runtime, Class<?> javaClass, String methodName, Class<?>[] argumentTypes) {
if ( "<init>".equals(methodName) ) {
if ( methodName.length() == 6 && "<init>".equals(methodName) ) {
return JavaConstructor.getMatchingConstructor(runtime, javaClass, argumentTypes);
}
// FIXME: do we really want 'declared' methods? includes private/protected, and does _not_
// include superclass methods
return JavaMethod.getMatchingDeclaredMethod(runtime, javaClass, methodName, argumentTypes);
}

private static Class<?>[] buildArgumentTypes(final Ruby runtime,
final IRubyObject[] args) throws ClassNotFoundException {
if ( args.length < 1 ) throw runtime.newArgumentError(args.length, 1);

Class<?>[] argumentTypes = new Class[args.length - 1];
for ( int i = 1; i < args.length; i++ ) {
private static Class<?>[] getArgumentTypes(final Ruby runtime, final IRubyObject[] args, final int offset) {
final int length = args.length; // offset == 0 || 1
if ( length == offset ) return EMPTY_CLASS_ARRAY;
final Class<?>[] argumentTypes = new Class[length - offset];
for ( int i = offset; i < length; i++ ) {
final IRubyObject arg = args[i];
final JavaClass type;
if ( arg instanceof JavaClass ) {
@@ -609,13 +612,13 @@ private static Class<?>[] buildArgumentTypes(final Ruby runtime,
} else {
type = forNameVerbose(runtime, arg.asJavaString());
}
argumentTypes[ i - 1 ] = type.javaClass();
argumentTypes[ i - offset ] = type.javaClass();
}
return argumentTypes;
}

// caching constructors, as they're accessed for each new instance
private volatile RubyArray constructors; // TODO seems not used that often?
private RubyArray constructors; // TODO seems not used that often?

@JRubyMethod
public RubyArray constructors() {
@@ -632,31 +635,36 @@ public RubyArray classes() {
@JRubyMethod
public RubyArray declared_classes() {
final Ruby runtime = getRuntime();
RubyArray result = runtime.newArray();
Class<?> javaClass = javaClass();
final Class<?> javaClass = javaClass();
try {
Class<?>[] classes = javaClass.getDeclaredClasses();
final RubyArray result = runtime.newArray(classes.length);
for (int i = 0; i < classes.length; i++) {
if (Modifier.isPublic(classes[i].getModifiers())) {
result.append(get(runtime, classes[i]));
result.append( get(runtime, classes[i]) );
}
}
} catch (SecurityException e) {
return result;
}
catch (SecurityException e) {
// restrictive security policy; no matter, we only want public
// classes anyway
try {
Class<?>[] classes = javaClass.getClasses();
final RubyArray result = runtime.newArray(classes.length);
for (int i = 0; i < classes.length; i++) {
if (javaClass == classes[i].getDeclaringClass()) {
result.append(get(runtime, classes[i]));
result.append( get(runtime, classes[i]) );
}
}
} catch (SecurityException e2) {
return result;
}
catch (SecurityException e2) {
// very restrictive policy (disallows Member.PUBLIC)
// we'd never actually get this far in that case
}
}
return result;
return RubyArray.newEmptyArray(runtime);
}

@JRubyMethod
@@ -676,7 +684,7 @@ private static RubyArray buildConstructors(final Ruby runtime, Constructor<?>[]
public JavaConstructor constructor(IRubyObject[] args) {
final Ruby runtime = getRuntime();
try {
Class<?>[] parameterTypes = buildClassArgs(runtime, args);
Class<?>[] parameterTypes = getArgumentTypes(runtime, args, 0);
@SuppressWarnings("unchecked")
Constructor<?> constructor = javaClass().getConstructor(parameterTypes);
return new JavaConstructor(runtime, constructor);
@@ -690,7 +698,7 @@ public JavaConstructor constructor(IRubyObject[] args) {
public JavaConstructor declared_constructor(IRubyObject[] args) {
final Ruby runtime = getRuntime();
try {
Class<?>[] parameterTypes = buildClassArgs(runtime, args);
Class<?>[] parameterTypes = getArgumentTypes(runtime, args, 0);
@SuppressWarnings("unchecked")
Constructor<?> constructor = javaClass().getDeclaredConstructor(parameterTypes);
return new JavaConstructor(runtime, constructor);
@@ -700,23 +708,6 @@ public JavaConstructor declared_constructor(IRubyObject[] args) {
}
}

private static Class<?>[] buildClassArgs(final Ruby runtime, IRubyObject[] args) {
Class<?>[] parameterTypes = new Class<?>[args.length];
for ( int i = 0; i < args.length; i++ ) {
final IRubyObject arg = args[i];
final JavaClass type;
if ( arg instanceof JavaClass ) {
type = (JavaClass) arg;
} else if ( arg.respondsTo("java_class") ) {
type = (JavaClass) arg.callMethod(runtime.getCurrentContext(), "java_class");
} else {
type = forNameVerbose(runtime, arg.asJavaString());
}
parameterTypes[i] = type.javaClass();
}
return parameterTypes;
}

@JRubyMethod
public JavaClass array_class() {
final Class<?> arrayClass = Array.newInstance(javaClass(), 0).getClass();
@@ -787,39 +778,62 @@ public IRubyObject concatArrays(ThreadContext context, JavaArray original, IRuby
return ArrayUtils.concatArraysDirect(context, original.getValue(), additional);
}

@Deprecated // no-longer-used
public IRubyObject javaArrayFromRubyArray(ThreadContext context, IRubyObject fromArray) {
Ruby runtime = context.runtime;
if (!(fromArray instanceof RubyArray)) {
if ( ! ( fromArray instanceof RubyArray ) ) {
final Ruby runtime = context.runtime;
throw runtime.newTypeError(fromArray, runtime.getArray());
}
return javaArrayFromRubyArray(context, (RubyArray) fromArray);
}

public final IRubyObject javaArrayFromRubyArray(ThreadContext context, RubyArray fromArray) {
final Ruby runtime = context.runtime;

Object newArray = javaArrayFromRubyArrayDirect(context, fromArray);

return new ArrayJavaProxy(runtime, Java.getProxyClassForObject(runtime, newArray), newArray, JavaUtil.getJavaConverter(javaClass()));
}

public Object javaArrayFromRubyArrayDirect(ThreadContext context, IRubyObject fromArray) {
Ruby runtime = context.runtime;
if (!(fromArray instanceof RubyArray)) {
throw runtime.newTypeError(fromArray, runtime.getArray());
}
RubyArray rubyArray = (RubyArray)fromArray;
Object newArray = Array.newInstance(javaClass(), rubyArray.size());
public final Object javaArrayFromRubyArrayDirect(ThreadContext context, RubyArray fromArray) {
final Ruby runtime = context.runtime;
final Class<?> type = javaClass();

final Object newArray = Array.newInstance(type, fromArray.size());

if (javaClass().isArray()) {
if ( type.isArray() ) {
// if it's an array of arrays, recurse with the component type
for (int i = 0; i < rubyArray.size(); i++) {
JavaClass componentType = component_type();
Object componentArray = componentType.javaArrayFromRubyArrayDirect(context, rubyArray.eltInternal(i));
ArrayUtils.setWithExceptionHandlingDirect(runtime, newArray, i, componentArray);
for ( int i = 0; i < fromArray.size(); i++ ) {
final Class<?> nestedType = type.getComponentType();
final IRubyObject element = fromArray.eltInternal(i);
final Object nestedArray;
if ( element instanceof RubyArray ) { // recurse
JavaClass componentType = JavaClass.get(runtime, nestedType);
nestedArray = componentType.javaArrayFromRubyArrayDirect(context, element);
}
else if ( type.isInstance(element) ) {
nestedArray = element;
}
else { // still try (nested) toJava conversion :
nestedArray = element.toJava(type);
}
ArrayUtils.setWithExceptionHandlingDirect(runtime, newArray, i, nestedArray);
}
} else {
ArrayUtils.copyDataToJavaArrayDirect(context, rubyArray, newArray);
ArrayUtils.copyDataToJavaArrayDirect(context, fromArray, newArray);
}

return newArray;
}

public final Object javaArrayFromRubyArrayDirect(ThreadContext context, IRubyObject fromArray) {
if ( ! ( fromArray instanceof RubyArray ) ) {
final Ruby runtime = context.runtime;
throw runtime.newTypeError(fromArray, runtime.getArray());
}
return javaArrayFromRubyArrayDirect(context, (RubyArray) fromArray);
}

@JRubyMethod
public RubyArray fields() {
return buildFieldResults(getRuntime(), javaClass().getFields());
18 changes: 17 additions & 1 deletion core/src/main/java/org/jruby/javasupport/JavaConstructor.java
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.RubyString;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ObjectAllocator;
@@ -117,19 +118,32 @@ public static JavaConstructor getMatchingConstructor(final Ruby runtime,
return null; // no matching ctor found
}

@Override
public final boolean equals(Object other) {
return other instanceof JavaConstructor &&
this.constructor.equals( ((JavaConstructor) other).constructor );
}

@Override
public final int hashCode() {
return constructor.hashCode();
}

@Override // not-used
protected String nameOnInspection() {
return getType().toString();
}

@JRubyMethod
public RubyString inspect() {
StringBuilder str = new StringBuilder();
str.append("#<");
str.append( getType().toString() );
inspectParameterTypes(str, this);
str.append(">");
return getRuntime().newString( str.toString() );
}

//@Override
//public final int getArity() {
// return parameterTypes.length;
@@ -311,5 +325,7 @@ public Object newInstanceDirect(ThreadContext context, Object arg0, Object arg1,
return handleThrowable(context, t);
}
}


boolean isConstructor() { return true; } // for error message in base class

}
27 changes: 22 additions & 5 deletions core/src/main/java/org/jruby/javasupport/JavaField.java
Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@
import org.jruby.RubyString;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
@@ -112,12 +113,16 @@ public IRubyObject field_type() {

@JRubyMethod
public IRubyObject value(ThreadContext context, IRubyObject object) {
Ruby runtime = context.runtime;
final Ruby runtime = context.runtime;

Object javaObject = null;
final Object javaObject;
if ( ! Modifier.isStatic( field.getModifiers() ) ) {
javaObject = JavaUtil.unwrapJavaValue(runtime, object, "not a java object");
javaObject = unwrapJavaObject(object);
}
else {
javaObject = null;
}

try {
return convertToRuby(runtime, field.get(javaObject));
}
@@ -128,10 +133,14 @@ public IRubyObject value(ThreadContext context, IRubyObject object) {

@JRubyMethod
public IRubyObject set_value(IRubyObject object, IRubyObject value) {
Object javaObject = null;
final Object javaObject;
if ( ! Modifier.isStatic( field.getModifiers() ) ) {
javaObject = JavaUtil.unwrapJavaValue(getRuntime(), object, "not a java object: " + object);
javaObject = unwrapJavaObject(object);
}
else {
javaObject = null;
}

final Object javaValue = convertValueToJava(value);
try {
field.set(javaObject, javaValue);
@@ -191,6 +200,14 @@ public AccessibleObject accessibleObject() {
return field;
}

private Object unwrapJavaObject(final IRubyObject object) throws RaiseException {
Object javaObject = JavaUtil.unwrapJavaValue(object);
if ( javaObject == null ) {
throw getRuntime().newTypeError("not a java object: " + object);
}
return javaObject;
}

private Object convertValueToJava(IRubyObject value) {
Object val = value.dataGetStruct();
if ( val instanceof JavaObject ) value = (IRubyObject) val;
74 changes: 47 additions & 27 deletions core/src/main/java/org/jruby/javasupport/JavaMethod.java
Original file line number Diff line number Diff line change
@@ -36,6 +36,13 @@
***** END LICENSE BLOCK *****/
package org.jruby.javasupport;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

import org.jruby.Ruby;
import org.jruby.RubyBoolean;
import org.jruby.RubyClass;
@@ -51,16 +58,11 @@
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.CodegenUtils;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import static org.jruby.util.CodegenUtils.getBoxType;
import static org.jruby.util.CodegenUtils.prettyParams;

@JRubyClass(name="Java::JavaMethod")
public class JavaMethod extends JavaCallable {
@@ -97,7 +99,7 @@ public JavaMethod(Ruby runtime, Method method) {
this.isFinal = Modifier.isFinal(method.getModifiers());
final Class<?> returnType = method.getReturnType();
if (returnType.isPrimitive() && returnType != void.class) {
this.boxedReturnType = CodegenUtils.getBoxType(returnType);
this.boxedReturnType = getBoxType(returnType);
} else {
this.boxedReturnType = returnType;
}
@@ -122,26 +124,28 @@ public JavaMethod(Ruby runtime, Method method) {
returnConverter = JavaUtil.getJavaConverter(returnType);
}

@Deprecated // no-longer used
public static JavaMethod create(Ruby runtime, Method method) {
return new JavaMethod(runtime, method);
}

@Deprecated // no-longer used
public static JavaMethod create(Ruby runtime, Class<?> javaClass, String methodName, Class<?>[] argumentTypes) {
try {
Method method = javaClass.getMethod(methodName, argumentTypes);
return create(runtime, method);
} catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'",
methodName);
return create(runtime, javaClass.getMethod(methodName, argumentTypes));
}
catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'", methodName);
}
}

@Deprecated // no-longer used
public static JavaMethod createDeclared(Ruby runtime, Class<?> javaClass, String methodName, Class<?>[] argumentTypes) {
try {
return create(runtime, javaClass.getDeclaredMethod(methodName, argumentTypes));
} catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'",
methodName);
}
catch (NoSuchMethodException e) {
throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'", methodName);
}
}

@@ -150,17 +154,17 @@ public static JavaMethod getMatchingDeclaredMethod(Ruby runtime, Class<?> javaCl
// include superclass methods. also, the getDeclared calls may throw SecurityException if
// we're running under a restrictive security policy.
try {
return create(runtime, javaClass.getDeclaredMethod(methodName, argumentTypes));
return new JavaMethod(runtime, javaClass.getDeclaredMethod(methodName, argumentTypes));
}
catch (NoSuchMethodException e) {
// search through all declared methods to find a closest match
MethodSearch: for (Method method : javaClass.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
MethodSearch: for ( Method method : javaClass.getDeclaredMethods() ) {
if ( method.getName().equals(methodName) ) {
Class<?>[] targetTypes = method.getParameterTypes();

// for zero args case we can stop searching
if (targetTypes.length == 0 && argumentTypes.length == 0) {
return create(runtime, method);
return new JavaMethod(runtime, method);
}

TypeScan: for (int i = 0; i < argumentTypes.length; i++) {
@@ -175,7 +179,7 @@ public static JavaMethod getMatchingDeclaredMethod(Ruby runtime, Class<?> javaCl

// if we get here, we found a matching method, use it
// TODO: choose narrowest method by continuing to search
return create(runtime, method);
return new JavaMethod(runtime, method);
}
}
}
@@ -221,10 +225,12 @@ public IRubyObject invoke(ThreadContext context, IRubyObject[] args) {
return invokeWithExceptionHandling(context, method, null, arguments);
}

Object javaInvokee = null;

final Object javaInvokee;
if (!isStatic()) {
javaInvokee = JavaUtil.unwrapJavaValue(getRuntime(), invokee, "invokee not a java object");
javaInvokee = JavaUtil.unwrapJavaValue(invokee);
if ( javaInvokee == null ) {
throw getRuntime().newTypeError("invokee not a java object");
}

if ( ! method.getDeclaringClass().isInstance(javaInvokee) ) {
throw getRuntime().newTypeError(
@@ -247,6 +253,10 @@ public IRubyObject invoke(ThreadContext context, IRubyObject[] args) {
}
}
}
else {
javaInvokee = null;
}

return invokeWithExceptionHandling(context, method, javaInvokee, arguments);
}

@@ -546,9 +556,19 @@ public final boolean isVarArgs() {
return method.isVarArgs();
}

@Override
@Override // not used
protected String nameOnInspection() {
return "#<" + getType().toString() + "/" + method.getName() + "(";
return getType().toString() + '/' + method.getName();
}

@JRubyMethod
public RubyString inspect() {
StringBuilder str = new StringBuilder();
str.append("#<");
str.append( getType().toString() ).append('/').append(method.getName());
inspectParameterTypes(str, this);
str.append(">");
return getRuntime().newString( str.toString() );
}

@JRubyMethod(name = "static?")
@@ -649,6 +669,6 @@ public static RaiseException newMethodNotFoundError(Ruby runtime, Class target,
}

public static RaiseException newArgSizeMismatchError(Ruby runtime, Class ... argTypes) {
return runtime.newArgumentError("argument count mismatch for method signature " + CodegenUtils.prettyParams(argTypes));
return runtime.newArgumentError("argument count mismatch for method signature " + prettyParams(argTypes));
}
}
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/javasupport/JavaSupport.java
Original file line number Diff line number Diff line change
@@ -103,6 +103,8 @@ public abstract class JavaSupport {

public abstract RubyClass getJavaConstructorClass();

public abstract RubyClass getJavaProxyConstructorClass();

public abstract Map<Set<?>, JavaProxyClass> getJavaProxyClassCache();

public abstract ClassValue<ThreadLocal<RubyModule>> getUnfinishedProxyClassCache();
7 changes: 7 additions & 0 deletions core/src/main/java/org/jruby/javasupport/JavaSupportImpl.java
Original file line number Diff line number Diff line change
@@ -92,6 +92,7 @@ public IRubyObject allocateProxy(Object javaObject, RubyClass clazz) {
private RubyClass arrayProxyClass;
private RubyClass concreteProxyClass;
private RubyClass mapJavaProxy;
private RubyClass javaProxyConstructorClass;

private final Map<String, JavaClass> nameClassMap = new HashMap<String, JavaClass>(64);

@@ -240,6 +241,12 @@ public RubyClass getJavaObjectClass() {
return javaObjectClass = getJavaModule().getClass("JavaObject");
}

public RubyClass getJavaProxyConstructorClass() {
RubyClass clazz;
if ((clazz = javaProxyConstructorClass) != null) return clazz;
return javaProxyConstructorClass = getJavaModule().getClass("JavaProxyConstructor");
}

public JavaClass getObjectJavaClass() {
return objectJavaClass;
}
576 changes: 288 additions & 288 deletions core/src/main/java/org/jruby/javasupport/JavaUtil.java

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions core/src/main/java/org/jruby/javasupport/ParameterTypes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2015 The JRuby Team
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.javasupport;

/**
* Represents Java (callable) parameter types
*
* @see JavaCallable
*/
public interface ParameterTypes {
Class<?>[] getParameterTypes();
Class<?>[] getExceptionTypes();
167 changes: 79 additions & 88 deletions core/src/main/java/org/jruby/javasupport/proxy/JavaProxyClass.java
Original file line number Diff line number Diff line change
@@ -63,6 +63,9 @@
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.builtin.IRubyObject;

import static org.jruby.javasupport.JavaClass.EMPTY_CLASS_ARRAY;
import static org.jruby.javasupport.JavaCallable.inspectParameterTypes;

/**
* Generalized proxy for classes and interfaces.
*
@@ -82,18 +85,14 @@
public class JavaProxyClass extends JavaProxyReflectionObject {
static ThreadLocal<Ruby> runtimeTLS = new ThreadLocal<Ruby>();

static final Class[] EMPTY_CLASS_ARRAY = new Class[0];

private final Class proxyClass;
private final ArrayList<JavaProxyMethod> methods = new ArrayList<JavaProxyMethod>();
private final HashMap<String, List<JavaProxyMethod>> methodMap = new HashMap<String, List<JavaProxyMethod>>();
private final RubyArray constructors;
private final HashMap<String, ArrayList<JavaProxyMethod>> methodMap = new HashMap<String, ArrayList<JavaProxyMethod>>();

/* package scope */
JavaProxyClass(Class proxyClass) {
JavaProxyClass(final Class<?> proxyClass) {
super(getThreadLocalRuntime(), getThreadLocalRuntime().getModule("Java").getClass("JavaProxyClass"));
this.proxyClass = proxyClass;
this.constructors = buildRubyArray( getConstructors() );
}

@Override
@@ -130,7 +129,7 @@ public static JavaProxyClass getProxyClass(Ruby runtime, Class superClass,

public static JavaProxyClass getProxyClass(Ruby runtime, Class superClass,
Class[] interfaces) throws InvocationTargetException {
return getProxyClass(runtime,superClass,interfaces,null);
return getProxyClass(runtime, superClass, interfaces, null);
}

public static Object newProxyInstance(Ruby runtime, Class superClass, Class[] interfaces,
@@ -154,30 +153,29 @@ public Class getSuperclass() {
public Class[] getInterfaces() {
Class[] ifaces = proxyClass.getInterfaces();
Class[] result = new Class[ifaces.length - 1];
int pos = 0;
for (int i = 0; i < ifaces.length; i++) {
if (ifaces[i] != InternalJavaProxy.class) {
result[pos++] = ifaces[i];
}
for ( int i = 0, j = 0; i < ifaces.length; i++ ) {
if ( ifaces[i] == InternalJavaProxy.class ) continue;
result[ j++ ] = ifaces[i];
}
return result;
}

public JavaProxyConstructor[] getConstructors() {
Constructor[] cons = proxyClass.getConstructors();
JavaProxyConstructor[] result = new JavaProxyConstructor[cons.length];
for (int i = 0; i < cons.length; i++) {
result[i] = new JavaProxyConstructor(getRuntime(), this, cons[i]);
final Ruby runtime = getRuntime();
final Constructor[] constructors = proxyClass.getConstructors();
JavaProxyConstructor[] result = new JavaProxyConstructor[constructors.length];
for ( int i = 0; i < constructors.length; i++ ) {
result[i] = new JavaProxyConstructor(runtime, this, constructors[i]);
}
return result;
}

public JavaProxyConstructor getConstructor(Class[] args)
throws SecurityException, NoSuchMethodException {
public JavaProxyConstructor getConstructor(final Class[] args)
throws SecurityException, NoSuchMethodException {

Class[] realArgs = new Class[args.length + 1];
final Class[] realArgs = new Class[args.length + 1];
System.arraycopy(args, 0, realArgs, 0, args.length);
realArgs[args.length] = JavaProxyInvocationHandler.class;
realArgs[ args.length ] = JavaProxyInvocationHandler.class;

@SuppressWarnings("unchecked")
Constructor<?> constructor = proxyClass.getConstructor(realArgs);
@@ -189,45 +187,52 @@ public JavaProxyMethod[] getMethods() {
}

public JavaProxyMethod getMethod(String name, Class[] parameterTypes) {
List<JavaProxyMethod> methods = methodMap.get(name);
if (methods != null) {
final List<JavaProxyMethod> methods = methodMap.get(name);
if ( methods != null && methods.size() > 0 ) {
for ( int i = methods.size(); --i >= 0; ) {
ProxyMethodImpl jpm = (ProxyMethodImpl) methods.get(i);
if (jpm.matches(name, parameterTypes)) return jpm;
ProxyMethodImpl impl = (ProxyMethodImpl) methods.get(i);
if ( impl.matches(name, parameterTypes) ) return impl;
}
}
return null;
}

/** return the class of instances of this proxy class */
Class getProxyClass() {
return proxyClass;
}
final Class getProxyClass() { return proxyClass; }

@Override
public Class getJavaClass() {
return proxyClass;
}

@JRubyClass(name="JavaProxy::JavaProxyMethod")
@JRubyClass(name="Java::JavaProxyMethod")
public static class ProxyMethodImpl extends JavaProxyReflectionObject
implements JavaProxyMethod {

private final Method method;
private final Method superMethod;
private final Class[] parameterTypes;

private final JavaProxyClass clazz;
private final JavaProxyClass proxyClass;

private Object state;

public static RubyClass createJavaProxyMethodClass(Ruby runtime, RubyModule Java) {
RubyClass JavaProxyMethod = Java.defineClassUnder("JavaProxyMethod",
runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);

JavaProxyReflectionObject.registerRubyMethods(runtime, JavaProxyMethod);
JavaProxyMethod.defineAnnotatedMethods(ProxyMethodImpl.class);
return JavaProxyMethod;
}

public ProxyMethodImpl(Ruby runtime, final JavaProxyClass clazz,
final Method method, final Method superMethod) {
super(runtime, getJavaProxyMethod(runtime));
this.method = method;
this.parameterTypes = method.getParameterTypes();
this.superMethod = superMethod;
this.clazz = clazz;
this.proxyClass = clazz;
}

private static RubyClass getJavaProxyMethod(final Ruby runtime) {
@@ -262,15 +267,15 @@ public String getName() {
return method.getName();
}

public Class<?>[] getExceptionTypes() {
public final Class<?>[] getExceptionTypes() {
return method.getExceptionTypes();
}

public Class<?>[] getParameterTypes() {
public final Class<?>[] getParameterTypes() {
return parameterTypes;
}

public boolean isVarArgs() {
public final boolean isVarArgs() {
return method.isVarArgs();
}

@@ -314,37 +319,26 @@ public Object defaultResult() {
return null;
}

public boolean matches(String name, Class[] parameterTypes) {
public final boolean matches(final String name, final Class<?>[] parameterTypes) {
return method.getName().equals(name) && Arrays.equals(this.parameterTypes, parameterTypes);
}

public Class getReturnType() {
public final Class<?> getReturnType() {
return method.getReturnType();
}

public static RubyClass createJavaProxyMethodClass(Ruby runtime, RubyModule javaProxyModule) {
RubyClass result = javaProxyModule.defineClassUnder("JavaProxyMethod",
runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);

JavaProxyReflectionObject.registerRubyMethods(runtime, result);

result.defineAnnotatedMethods(ProxyMethodImpl.class);

return result;
}

public RubyObject name() {
return getRuntime().newString(getName());
}

@JRubyMethod(name = "declaring_class")
public JavaProxyClass getDeclaringClass() {
return clazz;
public final JavaProxyClass getDeclaringClass() {
return proxyClass;
}

@JRubyMethod
public RubyArray argument_types() {
return buildRubyArray(getParameterTypes());
return toRubyArray(getParameterTypes());
}

@JRubyMethod(name = "super?")
@@ -357,25 +351,20 @@ public RubyFixnum arity() {
return getRuntime().newFixnum(getArity());
}

@Deprecated
protected String nameOnInspection() {
return getDeclaringClass().nameOnInspection() + "/" + getName();
}

@Override
@JRubyMethod
public IRubyObject inspect() {
StringBuilder result = new StringBuilder();
result.append(nameOnInspection());
result.append("(");
Class[] parameterTypes = getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
result.append(parameterTypes[i].getName());
if (i < parameterTypes.length - 1) {
result.append(',');
}
}
result.append(")>");
return getRuntime().newString(result.toString());
public RubyString inspect() {
StringBuilder str = new StringBuilder();
str.append("#<");
str.append( getDeclaringClass().nameOnInspection() ).append('/').append( getName() );
inspectParameterTypes(str, this);
str.append(">");
return getRuntime().newString( str.toString() );
}

@JRubyMethod(name = "invoke", rest = true)
@@ -425,8 +414,7 @@ private int getArity() {
}

@SuppressWarnings("unchecked")
JavaProxyMethod initMethod(final String name,
final String desc, final boolean hasSuper) {
JavaProxyMethod initMethod(final String name, final String desc, final boolean hasSuper) {
final Class proxy = this.proxyClass;
try {
Class[] paramTypes = parse(proxy.getClassLoader(), desc);
@@ -439,7 +427,7 @@ JavaProxyMethod initMethod(final String name,
JavaProxyMethod proxyMethod = new ProxyMethodImpl(getRuntime(), this, method, superMethod);
methods.add(proxyMethod);

List<JavaProxyMethod> methodsWithName = this.methodMap.get(name);
ArrayList<JavaProxyMethod> methodsWithName = this.methodMap.get(name);
if (methodsWithName == null) {
methodsWithName = new ArrayList<JavaProxyMethod>(2);
methodMap.put(name, methodsWithName);
@@ -459,8 +447,7 @@ JavaProxyMethod initMethod(final String name,
}
}

private static Class[] parse(final ClassLoader loader, String desc)
throws ClassNotFoundException {
private static Class[] parse(final ClassLoader loader, String desc) throws ClassNotFoundException {
final List<Class> types = new ArrayList<Class>();
int idx = 1;
while (desc.charAt(idx) != ')') {
@@ -517,15 +504,24 @@ public Class run() throws ClassNotFoundException {
// Ruby-level methods
//

public static RubyClass createJavaProxyClassClass(final Ruby runtime,
final RubyModule Java) {
RubyClass javaProxyClass = Java.defineClassUnder("JavaProxyClass",
@Deprecated
public static void createJavaProxyModule(Ruby runtime) {
createJavaProxyClasses(runtime, runtime.getJavaSupport().getJavaModule());
}

public static void createJavaProxyClasses(final Ruby runtime, final RubyModule Java) {
JavaProxyClass.createJavaProxyClassClass(runtime, Java);
ProxyMethodImpl.createJavaProxyMethodClass(runtime, Java);
JavaProxyConstructor.createJavaProxyConstructorClass(runtime, Java);
}

public static RubyClass createJavaProxyClassClass(final Ruby runtime, final RubyModule Java) {
RubyClass JavaProxyClass = Java.defineClassUnder("JavaProxyClass",
runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR
);

JavaProxyReflectionObject.registerRubyMethods(runtime, javaProxyClass);
javaProxyClass.defineAnnotatedMethods(JavaProxyClass.class);
return javaProxyClass;
JavaProxyReflectionObject.registerRubyMethods(runtime, JavaProxyClass);
JavaProxyClass.defineAnnotatedMethods(JavaProxyClass.class);
return JavaProxyClass;
}

@JRubyMethod(meta = true)
@@ -738,29 +734,24 @@ public RubyObject superclass() {

@JRubyMethod
public RubyArray methods() {
return buildRubyArray(getMethods());
return toRubyArray(getMethods());
}

@JRubyMethod
public RubyArray interfaces() {
return buildRubyArray(getInterfaces());
}

@JRubyMethod
public RubyArray constructors() {
return this.constructors;
return toRubyArray(getInterfaces());
}

public static void createJavaProxyModule(Ruby runtime) {
// TODO Auto-generated method stub
private RubyArray constructors;

RubyModule javaProxyModule = runtime.getJavaSupport().getJavaModule();
JavaProxyClass.createJavaProxyClassClass(runtime, javaProxyModule);
ProxyMethodImpl.createJavaProxyMethodClass(runtime, javaProxyModule);
JavaProxyConstructor.createJavaProxyConstructorClass(runtime, javaProxyModule);
@JRubyMethod
public final RubyArray constructors() {
final RubyArray constructors = this.constructors;
if ( constructors != null ) return constructors;
return this.constructors = toRubyArray( getConstructors() );
}

public String nameOnInspection() {
public final String nameOnInspection() {
return "[Proxy:" + getSuperclass().getName() + "]";
}
}
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@
import org.jruby.util.cli.Options;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
import static org.jruby.javasupport.proxy.JavaProxyClass.EMPTY_CLASS_ARRAY;
import static org.jruby.javasupport.JavaClass.EMPTY_CLASS_ARRAY;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
Loading

0 comments on commit 841df04

Please sign in to comment.