package org.jruby.javasupport;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyBoolean;
import org.jruby.RubyClass;
import org.jruby.RubyInteger;
import org.jruby.RubyModule;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.java.addons.ClassJavaAddons;
import org.jruby.java.proxies.ArrayJavaProxy;
import org.jruby.java.proxies.ConcreteJavaProxy;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.java.util.ArrayUtils;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.CodegenUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static org.jruby.RubyModule.undefinedMethodMessage;
import static org.jruby.util.RubyStringBuilder.ids;
@JRubyClass(name="Java::JavaClass", parent="Java::JavaObject", include = "Comparable")
public class JavaClass extends JavaObject {
public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
public JavaClass(final Ruby runtime, final Class<?> klass) {
this(runtime, runtime.getJavaSupport().getJavaClassClass(), klass);
}
JavaClass(final Ruby runtime, final RubyClass javaClassProxy, final Class<?> klass) {
super(runtime, javaClassProxy, klass);
}
@Override
public final boolean equals(Object other) {
if ( this == other ) return true;
return other instanceof JavaClass && this.getValue() == ((JavaClass) other).getValue();
}
@Override
public final int hashCode() {
return getValue().hashCode();
}
public final RubyModule getProxyModule() {
return Java.getProxyClass(getRuntime(), javaClass());
}
public final RubyClass getProxyClass() {
return (RubyClass) Java.getProxyClass(getRuntime(), javaClass());
}
private IRubyObject addProxyExtender(final ThreadContext context, final IRubyObject extender) {
if ( ! extender.respondsTo("extend_proxy") ) {
throw context.runtime.newTypeError("proxy extender must have an extend_proxy method");
}
RubyModule proxy = Java.getProxyClass(context.runtime, javaClass());
return extender.callMethod(context, "extend_proxy", proxy);
}
@JRubyMethod(required = 1)
public IRubyObject extend_proxy(final ThreadContext context, IRubyObject extender) {
addProxyExtender(context, extender);
return context.nil;
}
public static JavaClass get(final Ruby runtime, final Class<?> klass) {
return runtime.getJavaSupport().getJavaClassFromCache(klass);
}
@Deprecated
public static RubyArray getRubyArray(Ruby runtime, Class<?>[] classes) {
return toRubyArray(runtime, 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]);
}
return RubyArray.newArrayMayCopy(runtime, javaClasses);
}
public static RubyClass createJavaClassClass(final Ruby runtime, final RubyModule Java) {
return createJavaClassClass(runtime, Java, Java.getClass("JavaObject"));
}
static RubyClass createJavaClassClass(final Ruby runtime, final RubyModule Java, final RubyClass JavaObject) {
RubyClass JavaClass = Java.defineClassUnder("JavaClass", JavaObject, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
JavaClass.includeModule(runtime.getModule("Comparable"));
JavaClass.defineAnnotatedMethods(JavaClass.class);
JavaClass.getMetaClass().undefineMethod("new");
JavaClass.getMetaClass().undefineMethod("allocate");
return JavaClass;
}
public final Class javaClass() {
return (Class<?>) getValue();
}
public static Class<?> getJavaClass(final ThreadContext context, final RubyModule proxy) {
return getJavaClassIfProxy(context, proxy);
}
public static Class<?> getJavaClassIfProxy(final ThreadContext context, final RubyModule proxy) {
JavaClass javaClass = getJavaClassIfProxyImpl(context, proxy);
return javaClass == null ? null : javaClass.javaClass();
}
private static JavaClass getJavaClassIfProxyImpl(final ThreadContext context, final RubyModule proxy) {
final IRubyObject java_class = java_class(context, proxy);
return ( java_class instanceof JavaClass ) ? (JavaClass) java_class : null;
}
public static boolean isProxyType(final ThreadContext context, final RubyModule proxy) {
return getJavaClassIfProxyImpl(context, proxy) != null;
}
public static IRubyObject java_class(final ThreadContext context, final RubyModule type) {
IRubyObject java_class = type.getInstanceVariable("@java_class");
if ( java_class == null ) {
if ( type.respondsTo("java_class") ) {
java_class = Helpers.invoke(context, type, "java_class");
}
else java_class = context.nil;
}
return java_class;
}
public static JavaClass resolveType(final ThreadContext context, final IRubyObject type) {
if (type instanceof RubyString || type instanceof RubySymbol) {
final Ruby runtime = context.runtime;
final String className = type.toString();
JavaClass targetType = runtime.getJavaSupport().getNameClassMap().get(className);
if ( targetType == null ) targetType = JavaClass.forNameVerbose(runtime, className);
return targetType;
}
return resolveClassType(context, type);
}
private static JavaClass resolveClassType(final ThreadContext context, final IRubyObject type) {
if (type instanceof JavaProxy) {
final Object wrapped = ((JavaProxy) type).getObject();
if ( wrapped instanceof Class ) return JavaClass.get(context.runtime, (Class) wrapped);
return null;
}
if (type instanceof JavaClass) {
return (JavaClass) type;
}
if (type instanceof RubyModule) {
return getJavaClassIfProxyImpl(context, (RubyModule) type);
}
return null;
}
static boolean isPrimitiveName(final String name) {
return JavaUtil.getPrimitiveClass(name) != null;
}
public static JavaClass forNameVerbose(Ruby runtime, String className) {
Class<?> klass = null;
if (className.length() < 8 && Character.isLowerCase(className.charAt(0))) {
klass = JavaUtil.getPrimitiveClass(className);
}
synchronized (JavaClass.class) {
if (klass == null) {
klass = runtime.getJavaSupport().loadJavaClassVerbose(className);
}
return JavaClass.get(runtime, klass);
}
}
public static JavaClass forNameQuiet(Ruby runtime, String className) {
synchronized (JavaClass.class) {
Class<?> klass = runtime.getJavaSupport().loadJavaClassQuiet(className);
return JavaClass.get(runtime, klass);
}
}
@JRubyMethod(name = "for_name", required = 1, meta = true)
public static JavaClass for_name(IRubyObject recv, IRubyObject name) {
return for_name(recv, name.asJavaString());
}
static JavaClass for_name(IRubyObject recv, String name) {
return forNameVerbose(recv.getRuntime(), name);
}
@JRubyMethod
public RubyModule ruby_class() {
return Java.getProxyClass(getRuntime(), javaClass());
}
@JRubyMethod(name = "public?")
public RubyBoolean public_p() {
return getRuntime().newBoolean(Modifier.isPublic(javaClass().getModifiers()));
}
@JRubyMethod(name = "protected?")
public RubyBoolean protected_p() {
return getRuntime().newBoolean(Modifier.isProtected(javaClass().getModifiers()));
}
@JRubyMethod(name = "private?")
public RubyBoolean private_p() {
return getRuntime().newBoolean(Modifier.isPrivate(javaClass().getModifiers()));
}
@JRubyMethod(name = "final?")
public RubyBoolean final_p() {
return getRuntime().newBoolean(Modifier.isFinal(javaClass().getModifiers()));
}
@JRubyMethod(name = "interface?")
public RubyBoolean interface_p() {
return getRuntime().newBoolean(javaClass().isInterface());
}
@JRubyMethod(name = "array?")
public RubyBoolean array_p() {
return getRuntime().newBoolean(javaClass().isArray());
}
@JRubyMethod(name = "enum?")
public RubyBoolean enum_p() {
return getRuntime().newBoolean(javaClass().isEnum());
}
@JRubyMethod(name = "annotation?")
public RubyBoolean annotation_p() {
return getRuntime().newBoolean(javaClass().isAnnotation());
}
@JRubyMethod(name = "anonymous_class?")
public RubyBoolean anonymous_class_p() {
return getRuntime().newBoolean(javaClass().isAnonymousClass());
}
@JRubyMethod(name = "local_class?")
public RubyBoolean local_class_p() {
return getRuntime().newBoolean(javaClass().isLocalClass());
}
@JRubyMethod(name = "member_class?")
public RubyBoolean member_class_p() {
return getRuntime().newBoolean(javaClass().isMemberClass());
}
@JRubyMethod(name = "synthetic?")
public IRubyObject synthetic_p() {
return getRuntime().newBoolean(javaClass().isSynthetic());
}
@JRubyMethod(name = {"name", "to_s"})
public RubyString name() {
return getRuntime().newString(javaClass().getName());
}
@Override
@JRubyMethod
public RubyString inspect() {
return getRuntime().newString("class " + javaClass().getName());
}
@JRubyMethod
public IRubyObject canonical_name() {
String canonicalName = javaClass().getCanonicalName();
if (canonicalName != null) {
return getRuntime().newString(canonicalName);
}
return getRuntime().getNil();
}
@JRubyMethod(name = "package")
public IRubyObject get_package() {
return Java.getInstance(getRuntime(), javaClass().getPackage());
}
@JRubyMethod
public IRubyObject class_loader() {
return Java.getInstance(getRuntime(), javaClass().getClassLoader());
}
@JRubyMethod
public IRubyObject protection_domain() {
return Java.getInstance(getRuntime(), javaClass().getProtectionDomain());
}
@JRubyMethod(required = 1)
public IRubyObject resource(IRubyObject name) {
return Java.getInstance(getRuntime(), javaClass().getResource(name.asJavaString()));
}
@JRubyMethod(required = 1)
public IRubyObject resource_as_stream(IRubyObject name) {
return Java.getInstance(getRuntime(), javaClass().getResourceAsStream(name.asJavaString()));
}
@JRubyMethod(required = 1)
public IRubyObject resource_as_string(IRubyObject name) {
InputStream in = javaClass().getResourceAsStream(name.asJavaString());
if (in == null) return getRuntime().getNil();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
int len;
byte[] buf = new byte[4096];
while ((len = in.read(buf)) >= 0) {
out.write(buf, 0, len);
}
} catch (IOException e) {
throw getRuntime().newIOErrorFromException(e);
} finally {
try {in.close();} catch (IOException ioe) {}
}
return getRuntime().newString(new ByteList(out.toByteArray(), false));
}
@SuppressWarnings("unchecked")
@JRubyMethod(required = 1)
public IRubyObject annotation(final IRubyObject annoClass) {
final Ruby runtime = getRuntime();
if ( ! ( annoClass instanceof JavaClass ) ) {
throw runtime.newTypeError(annoClass, runtime.getJavaSupport().getJavaClassClass());
}
final Class annotation = ((JavaClass) annoClass).javaClass();
return Java.getInstance(runtime, javaClass().getAnnotation(annotation));
}
@JRubyMethod
public IRubyObject annotations() {
return Java.getInstance(getRuntime(), javaClass().getAnnotations());
}
@JRubyMethod(name = "annotations?")
public RubyBoolean annotations_p() {
return getRuntime().newBoolean(javaClass().getAnnotations().length > 0);
}
@JRubyMethod
public IRubyObject declared_annotations() {
return Java.getInstance(getRuntime(), javaClass().getDeclaredAnnotations());
}
@JRubyMethod(name = "declared_annotations?")
public RubyBoolean declared_annotations_p() {
return getRuntime().newBoolean(javaClass().getDeclaredAnnotations().length > 0);
}
@SuppressWarnings("unchecked")
@JRubyMethod(name = "annotation_present?", required = 1)
public IRubyObject annotation_present_p(final IRubyObject annoClass) {
final Ruby runtime = getRuntime();
if ( ! ( annoClass instanceof JavaClass ) ) {
throw runtime.newTypeError(annoClass, runtime.getJavaSupport().getJavaClassClass());
}
final Class annotation = ((JavaClass) annoClass).javaClass();
return runtime.newBoolean( javaClass().isAnnotationPresent(annotation) );
}
@JRubyMethod
public IRubyObject modifiers() {
return getRuntime().newFixnum(javaClass().getModifiers());
}
@JRubyMethod
public IRubyObject declaring_class() {
Class<?> clazz = javaClass().getDeclaringClass();
if (clazz != null) {
return JavaClass.get(getRuntime(), clazz);
}
return getRuntime().getNil();
}
@JRubyMethod
public IRubyObject enclosing_class() {
return Java.getInstance(getRuntime(), javaClass().getEnclosingClass());
}
@JRubyMethod
public IRubyObject enclosing_constructor() {
Constructor<?> ctor = javaClass().getEnclosingConstructor();
if (ctor != null) {
return new JavaConstructor(getRuntime(), ctor);
}
return getRuntime().getNil();
}
@JRubyMethod
public IRubyObject enclosing_method() {
Method meth = javaClass().getEnclosingMethod();
if (meth != null) {
return new JavaMethod(getRuntime(), meth);
}
return getRuntime().getNil();
}
@JRubyMethod
public IRubyObject enum_constants() {
return Java.getInstance(getRuntime(), javaClass().getEnumConstants());
}
@JRubyMethod
public IRubyObject generic_interfaces() {
return Java.getInstance(getRuntime(), javaClass().getGenericInterfaces());
}
@JRubyMethod
public IRubyObject generic_superclass() {
return Java.getInstance(getRuntime(), javaClass().getGenericSuperclass());
}
@JRubyMethod
public IRubyObject type_parameters() {
return Java.getInstance(getRuntime(), javaClass().getTypeParameters());
}
@JRubyMethod
public IRubyObject signers() {
return Java.getInstance(getRuntime(), javaClass().getSigners());
}
public static String getSimpleName(Class<?> clazz) {
if (clazz.isArray()) {
return getSimpleName(clazz.getComponentType()) + "[]";
}
String className = clazz.getName();
int len = className.length();
int i = className.lastIndexOf('$');
if (i != -1) {
do {
i++;
} while (i < len && Character.isDigit(className.charAt(i)));
return className.substring(i);
}
return className.substring(className.lastIndexOf('.') + 1);
}
@JRubyMethod
public RubyString simple_name() {
return getRuntime().newString(getSimpleName(javaClass()));
}
@JRubyMethod
public IRubyObject superclass() {
Class<?> superclass = javaClass().getSuperclass();
if (superclass == null) {
return getRuntime().getNil();
}
return JavaClass.get(getRuntime(), superclass);
}
@JRubyMethod(name = "<=>", required = 1)
public IRubyObject op_cmp(IRubyObject other) {
final Class<?> thisClass = javaClass();
Class<?> otherClass = null;
if (other instanceof JavaClass) {
otherClass = ( (JavaClass) other ).javaClass();
}
else if (other instanceof ConcreteJavaProxy) {
ConcreteJavaProxy proxy = (ConcreteJavaProxy) other;
final Object wrapped = proxy.getObject();
if ( wrapped instanceof Class ) {
otherClass = (Class) wrapped;
}
}
if ( otherClass != null ) {
if ( thisClass == otherClass ) {
return getRuntime().newFixnum(0);
}
if ( otherClass.isAssignableFrom(thisClass) ) {
return getRuntime().newFixnum(-1);
}
if ( thisClass.isAssignableFrom(otherClass) ) {
return getRuntime().newFixnum(1);
}
}
return getRuntime().getNil();
}
@JRubyMethod
public RubyArray java_instance_methods() {
return toJavaMethods(javaClass().getMethods(), false);
}
@JRubyMethod
public RubyArray declared_instance_methods() {
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 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( new JavaMethod(runtime, method) );
}
}
return result;
}
@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 = getArgumentTypes(runtime, args, 1);
@SuppressWarnings("unchecked")
final Method method = javaClass().getMethod(methodName, argumentTypes);
return new JavaMethod(runtime, method);
}
catch (NoSuchMethodException e) {
throw runtime.newNameError(undefinedMethodMessage(runtime, ids(runtime, methodName), ids(runtime, javaClass().getName()), false), 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 = getArgumentTypes(runtime, args, 1);
@SuppressWarnings("unchecked")
final Method method = javaClass().getDeclaredMethod(methodName, argumentTypes);
return new JavaMethod(runtime, method);
}
catch (NoSuchMethodException e) {
throw runtime.newNameError(undefinedMethodMessage(runtime, ids(runtime, methodName), ids(runtime, javaClass().getName()), false), 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();
Class<?>[] argumentTypes = getArgumentTypes(runtime, args, 1);
JavaCallable callable = getMatchingCallable(runtime, javaClass(), methodName, argumentTypes);
if ( callable != null ) return callable;
throw runtime.newNameError(undefinedMethodMessage(runtime, ids(runtime, methodName), ids(runtime, javaClass().getName()), false), methodName);
}
public static JavaCallable getMatchingCallable(Ruby runtime, Class<?> javaClass, String methodName, Class<?>[] argumentTypes) {
if ( methodName.length() == 6 && "<init>".equals(methodName) ) {
return JavaConstructor.getMatchingConstructor(runtime, javaClass, argumentTypes);
}
return JavaMethod.getMatchingDeclaredMethod(runtime, javaClass, methodName, argumentTypes);
}
private static Class<?>[] getArgumentTypes(final Ruby runtime, final IRubyObject[] args, final int offset) {
final int length = args.length;
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 ) {
type = (JavaClass) arg;
} else if ( arg.respondsTo("java_class") ) {
type = (JavaClass) arg.callMethod(runtime.getCurrentContext(), "java_class");
} else {
type = forNameVerbose(runtime, arg.asJavaString());
}
argumentTypes[ i - offset ] = type.javaClass();
}
return argumentTypes;
}
private RubyArray constructors;
@JRubyMethod
public RubyArray constructors() {
final RubyArray constructors = this.constructors;
if ( constructors != null) return constructors;
return this.constructors = buildConstructors(getRuntime(), javaClass().getConstructors());
}
@JRubyMethod
public RubyArray classes() {
return toRubyArray(getRuntime(), javaClass().getClasses());
}
@JRubyMethod
public RubyArray declared_classes() {
final Ruby runtime = getRuntime();
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]) );
}
}
return result;
}
catch (SecurityException e) {
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]) );
}
}
return result;
}
catch (SecurityException e2) {
}
}
return RubyArray.newEmptyArray(runtime);
}
@JRubyMethod
public RubyArray declared_constructors() {
return buildConstructors(getRuntime(), javaClass().getDeclaredConstructors());
}
private static RubyArray buildConstructors(final Ruby runtime, Constructor<?>[] constructors) {
RubyArray result = RubyArray.newArray(runtime, constructors.length);
for ( int i = 0; i < constructors.length; i++ ) {
result.append( new JavaConstructor(runtime, constructors[i]) );
}
return result;
}
@JRubyMethod(rest = true)
public JavaConstructor constructor(IRubyObject[] args) {
final Ruby runtime = getRuntime();
try {
Class<?>[] parameterTypes = getArgumentTypes(runtime, args, 0);
@SuppressWarnings("unchecked")
Constructor<?> constructor = javaClass().getConstructor(parameterTypes);
return new JavaConstructor(runtime, constructor);
}
catch (NoSuchMethodException nsme) {
throw runtime.newNameError("no matching java constructor", null);
}
}
@JRubyMethod(rest = true)
public JavaConstructor declared_constructor(IRubyObject[] args) {
final Ruby runtime = getRuntime();
try {
Class<?>[] parameterTypes = getArgumentTypes(runtime, args, 0);
@SuppressWarnings("unchecked")
Constructor<?> constructor = javaClass().getDeclaredConstructor(parameterTypes);
return new JavaConstructor(runtime, constructor);
}
catch (NoSuchMethodException nsme) {
throw runtime.newNameError("no matching java constructor", null);
}
}
@JRubyMethod
public JavaClass array_class() {
final Class<?> arrayClass = Array.newInstance(javaClass(), 0).getClass();
return JavaClass.get(getRuntime(), arrayClass);
}
@JRubyMethod(required = 1)
public JavaObject new_array(IRubyObject lengthArgument) {
if (lengthArgument instanceof RubyInteger) {
int length = ((RubyInteger) lengthArgument).getIntValue();
return new JavaArray(getRuntime(), Array.newInstance(javaClass(), length));
}
else if (lengthArgument instanceof RubyArray) {
IRubyObject[] aryLengths = ((RubyArray)lengthArgument).toJavaArrayMaybeUnsafe();
final int length = aryLengths.length;
if (length == 0) {
throw getRuntime().newArgumentError("empty dimensions specifier for java array");
}
final int[] dimensions = new int[length];
for (int i = length; --i >= 0; ) {
IRubyObject dimLength = aryLengths[i];
if ( ! ( dimLength instanceof RubyInteger ) ) {
throw getRuntime().newTypeError(dimLength, getRuntime().getInteger());
}
dimensions[i] = ((RubyInteger) dimLength).getIntValue();
}
return new JavaArray(getRuntime(), Array.newInstance(javaClass(), dimensions));
}
else {
throw getRuntime().newArgumentError(
"invalid length or dimensions specifier for java array - must be Integer or Array of Integer");
}
}
public IRubyObject emptyJavaArray(ThreadContext context) {
return ArrayUtils.emptyJavaArrayDirect(context, javaClass());
}
public IRubyObject javaArraySubarray(ThreadContext context, JavaArray fromArray, int index, int size) {
return ArrayUtils.javaArraySubarrayDirect(context, getValue(), index, size);
}
public IRubyObject concatArrays(ThreadContext context, JavaArray original, JavaArray additional) {
return ArrayUtils.concatArraysDirect(context, original.getValue(), additional.getValue());
}
public IRubyObject concatArrays(ThreadContext context, JavaArray original, IRubyObject additional) {
return ArrayUtils.concatArraysDirect(context, original.getValue(), additional);
}
@Deprecated
public IRubyObject javaArrayFromRubyArray(ThreadContext context, IRubyObject fromArray) {
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 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 ( type.isArray() ) {
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 ) {
JavaClass componentType = JavaClass.get(runtime, nestedType);
nestedArray = componentType.javaArrayFromRubyArrayDirect(context, element);
}
else if ( type.isInstance(element) ) {
nestedArray = element;
}
else {
nestedArray = element.toJava(type);
}
ArrayUtils.setWithExceptionHandlingDirect(runtime, newArray, i, nestedArray);
}
} else {
ArrayUtils.copyDataToJavaArrayDirect(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());
}
@JRubyMethod
public RubyArray declared_fields() {
return buildFieldResults(getRuntime(), javaClass().getDeclaredFields());
}
private static RubyArray buildFieldResults(final Ruby runtime, Field[] fields) {
RubyArray result = runtime.newArray( fields.length );
for ( int i = 0; i < fields.length; i++ ) {
result.append( new JavaField(runtime, fields[i]) );
}
return result;
}
@JRubyMethod(required = 1)
public JavaField field(ThreadContext context, IRubyObject name) {
Class<?> javaClass = javaClass();
Ruby runtime = context.runtime;
String stringName = name.asJavaString();
try {
return new JavaField(runtime, javaClass.getField(stringName));
} catch (NoSuchFieldException nsfe) {
String newName = JavaUtil.getJavaCasedName(stringName);
if(newName != null) {
try {
return new JavaField(runtime, javaClass.getField(newName));
} catch (NoSuchFieldException nsfe2) {}
}
throw undefinedFieldError(runtime, javaClass.getName(), stringName);
}
}
@JRubyMethod(required = 1)
public JavaField declared_field(ThreadContext context, IRubyObject name) {
Class<?> javaClass = javaClass();
Ruby runtime = context.runtime;
String stringName = name.asJavaString();
try {
return new JavaField(runtime, javaClass.getDeclaredField(stringName));
} catch (NoSuchFieldException nsfe) {
String newName = JavaUtil.getJavaCasedName(stringName);
if(newName != null) {
try {
return new JavaField(runtime, javaClass.getDeclaredField(newName));
} catch (NoSuchFieldException nsfe2) {}
}
throw undefinedFieldError(runtime, javaClass.getName(), stringName);
}
}
public static RaiseException undefinedFieldError(Ruby runtime, String javaClassName, String name) {
return runtime.newNameError("undefined field '" + name + "' for class '" + javaClassName + "'", name);
}
@JRubyMethod
public RubyArray interfaces() {
return toRubyArray(getRuntime(), javaClass().getInterfaces());
}
@JRubyMethod(name = "primitive?")
public RubyBoolean primitive_p() {
return getRuntime().newBoolean( isPrimitive() );
}
boolean isPrimitive() { return javaClass().isPrimitive(); }
@JRubyMethod(name = "assignable_from?", required = 1)
public RubyBoolean assignable_from_p(IRubyObject other) {
if ( ! (other instanceof JavaClass) ) {
throw getRuntime().newTypeError("assignable_from requires JavaClass (" + other.getType() + " given)");
}
Class<?> otherClass = ((JavaClass) other).javaClass();
return isAssignableFrom(otherClass) ? getRuntime().getTrue() : getRuntime().getFalse();
}
public final boolean isAssignableFrom(final Class<?> clazz) {
return assignable(javaClass(), clazz);
}
public static boolean assignable(Class<?> target, Class<?> from) {
if ( target.isPrimitive() ) target = CodegenUtils.getBoxType(target);
else if ( from == Void.TYPE || target.isAssignableFrom(from) ) {
return true;
}
if ( from.isPrimitive() ) from = CodegenUtils.getBoxType(from);
if ( target.isAssignableFrom(from) ) return true;
if ( Number.class.isAssignableFrom(target) ) {
if ( Number.class.isAssignableFrom(from) ) {
return true;
}
if ( from == Character.class ) {
return true;
}
}
else if ( target == Character.class ) {
if ( Number.class.isAssignableFrom(from) ) {
return true;
}
}
return false;
}
@JRubyMethod
public JavaClass component_type() {
if ( ! javaClass().isArray() ) {
throw getRuntime().newTypeError("not a java array-class");
}
return JavaClass.get(getRuntime(), javaClass().getComponentType());
}
public static Constructor[] getConstructors(final Class<?> clazz) {
try {
return clazz.getConstructors();
}
catch (SecurityException e) { return new Constructor[0]; }
}
public static Class<?>[] getDeclaredClasses(final Class<?> clazz) {
try {
return clazz.getDeclaredClasses();
}
catch (SecurityException e) { return new Class<?>[0]; }
catch (NoClassDefFoundError cnfe) {
return new Class<?>[0];
}
}
public static Field[] getDeclaredFields(final Class<?> clazz) {
try {
return clazz.getDeclaredFields();
}
catch (SecurityException e) {
return getFields(clazz);
}
}
public static Field[] getFields(final Class<?> clazz) {
try {
return clazz.getFields();
}
catch (SecurityException e) { return new Field[0]; }
}
}