All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jruby.javasupport.ext.JavaLangReflect Maven / Gradle / Ivy

/***** BEGIN LICENSE BLOCK *****
 * Version: EPL 2.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Eclipse Public
 * License Version 2.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-v20.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) 2016 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.ext;

import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.javasupport.JavaObject;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.RubyStringBuilder;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

import static org.jruby.javasupport.JavaUtil.convertArguments;
import static org.jruby.javasupport.JavaUtil.convertJavaToUsableRubyObject;
import static org.jruby.util.Inspector.GT;
import static org.jruby.util.Inspector.inspectPrefix;

/**
 * Java::JavaLangReflect package extensions.
 *
 * @author kares
 */
public abstract class JavaLangReflect {

    public static void define(final Ruby runtime) {
        JavaExtensions.put(runtime, java.lang.reflect.AccessibleObject.class, (proxyClass) -> AccessibleObject.define(runtime, (RubyClass) proxyClass));
        JavaExtensions.put(runtime, java.lang.reflect.Constructor.class, (proxyClass) -> Constructor.define(runtime, (RubyClass) proxyClass));
        JavaExtensions.put(runtime, java.lang.reflect.Field.class, (proxyClass) -> Field.define(runtime, (RubyClass) proxyClass));
        JavaExtensions.put(runtime, java.lang.reflect.Method.class, (proxyClass) -> Method.define(runtime, (RubyClass) proxyClass));
    }

    @JRubyClass(name = "Java::JavaLangReflect::AccessibleObject")
    public static class AccessibleObject {

        static RubyClass define(final Ruby runtime, final RubyClass proxy) {
            proxy.defineAnnotatedMethods(AccessibleObject.class);
            return proxy;
        }

        @JRubyMethod
        public static IRubyObject inspect(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.AccessibleObject obj = JavaUtil.unwrapJavaObject(self);

            RubyString buf = inspectPrefix(context, self.getMetaClass());
            RubyStringBuilder.cat(context.runtime, buf, ' ');
            RubyStringBuilder.cat(context.runtime, buf, obj.toString());
            RubyStringBuilder.cat(context.runtime, buf, GT); // >

            return buf;
        }
    }

    @JRubyClass(name = "Java::JavaLangReflect::Constructor")
    public static class Constructor {

        static RubyClass define(final Ruby runtime, final RubyClass proxy) {
            proxy.defineAnnotatedMethods(Constructor.class);
            return proxy;
        }

        @JRubyMethod
        public static IRubyObject return_type(final ThreadContext context, final IRubyObject self) {
            return context.nil;
        }

        @JRubyMethod // alias argument_types parameter_types
        public static IRubyObject argument_types(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return convertJavaToUsableRubyObject(context.runtime, thiz.getParameterTypes());
        }

        // NOTE: (legacy) JavaConstructor compat - converting arguments
        @JRubyMethod(name = "newInstance", alias = "new_instance", rest = true)
        public static IRubyObject new_instance(final ThreadContext context, final IRubyObject self, final IRubyObject[] args) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            final Object[] javaArgs;
            if (args.length == 0) {
                javaArgs = NO_ARGS;
            } else {
                javaArgs = convertArguments(args, thiz.getParameterTypes(), 0);
            }
            try {
                return convertJavaToUsableRubyObject(context.runtime, thiz.newInstance(javaArgs));
            }
            catch (IllegalAccessException|InvocationTargetException|InstantiationException e) {
                Helpers.throwException(e); return null;
            }
        }

        // JavaUtilities::ModifiedShortcuts :

        @JRubyMethod(name = "public?")
        public static IRubyObject public_p(final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return isPublic(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "protected?")
        public static IRubyObject protected_p(final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return isProtected(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "private?")
        public static IRubyObject private_p(final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return isPrivate(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "final?")
        public static IRubyObject final_p(final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return isFinal(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "static?")
        public static IRubyObject static_p(final IRubyObject self) {
            final java.lang.reflect.Constructor thiz = JavaUtil.unwrapJavaObject(self);
            return isStatic(self, thiz.getModifiers());
        }

    }

    private static final Object[] NO_ARGS = new Object[0];

    @JRubyClass(name = "Java::JavaLangReflect::Method")
    public static class Method {

        static RubyClass define(final Ruby runtime, final RubyClass proxy) {
            proxy.defineAnnotatedMethods(Method.class);
            return proxy;
        }

        @JRubyMethod
        public static IRubyObject return_type(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return convertJavaToUsableRubyObject(context.runtime, thiz.getReturnType());
        }

        @JRubyMethod // alias argument_types parameter_types
        public static IRubyObject argument_types(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return convertJavaToUsableRubyObject(context.runtime, thiz.getParameterTypes());
        }

        @JRubyMethod(rest = true)
        public static IRubyObject invoke(final ThreadContext context, final IRubyObject self, final IRubyObject[] args) {
            final java.lang.reflect.Method method = JavaUtil.unwrapJavaObject(self);
            // NOTE: (legacy) JavaMethod compat - also worked with no arguments
            final Object target;
            final Object[] javaArgs;
            if (args.length == 0) {
                target = null;
                javaArgs = NO_ARGS;
            } else {
                target = unwrapJavaObject(args[0]);
                javaArgs = convertArguments(args, method.getParameterTypes(), 1);
            }
            try {
                return convertJavaToUsableRubyObject(context.runtime, method.invoke(target, javaArgs));
            }
            catch (IllegalAccessException|InvocationTargetException e) {
                Helpers.throwException(e); return null;
            }
        }

        @JRubyMethod(rest = true)
        public static IRubyObject invoke_static(final ThreadContext context, final IRubyObject self, final IRubyObject[] args) {
            final java.lang.reflect.Method method = JavaUtil.unwrapJavaObject(self);
            final Object[] javaArgs = convertArguments(args, method.getParameterTypes());
            try {
                return convertJavaToUsableRubyObject(context.runtime, method.invoke(null, javaArgs));
            }
            catch (IllegalAccessException|InvocationTargetException e) {
                Helpers.throwException(e); return null;
            }
        }

        //

        @JRubyMethod(name = "abstract?")
        public static IRubyObject abstract_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isAbstract(self, thiz.getModifiers());
        }

        // JavaUtilities::ModifiedShortcuts :

        @JRubyMethod(name = "public?")
        public static IRubyObject public_p(final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return isPublic(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "protected?")
        public static IRubyObject protected_p(final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return isProtected(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "private?")
        public static IRubyObject private_p(final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return isPrivate(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "final?")
        public static IRubyObject final_p(final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return isFinal(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "static?")
        public static IRubyObject static_p(final IRubyObject self) {
            final java.lang.reflect.Method thiz = JavaUtil.unwrapJavaObject(self);
            return isStatic(self, thiz.getModifiers());
        }

    }

    @JRubyClass(name = "Java::JavaLangReflect::Field")
    public static class Field {

        static RubyClass define(final Ruby runtime, final RubyClass proxy) {
            proxy.defineAnnotatedMethods(Field.class);
            return proxy;
        }

        @JRubyMethod
        public static IRubyObject value_type(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.Field field = JavaUtil.unwrapJavaObject(self);
            return convertJavaToUsableRubyObject(context.runtime, field.getType().getName());
        }

        @JRubyMethod // alias value get
        public static IRubyObject value(final ThreadContext context, final IRubyObject self, final IRubyObject obj) {
            final java.lang.reflect.Field field = JavaUtil.unwrapJavaObject(self);
            // NOTE: (legacy) JavaField compat - also worked when setting a static value
            final Object target = Modifier.isStatic(field.getModifiers()) ? null : unwrapJavaObject(obj);
            try {
                return convertJavaToUsableRubyObject(context.runtime, field.get(target));
            }
            catch (IllegalAccessException e) {
                Helpers.throwException(e); return null;
            }
        }

        @JRubyMethod // alias set_value set
        public static IRubyObject set_value(final ThreadContext context, final IRubyObject self, final IRubyObject obj,
            final IRubyObject value) {
            final java.lang.reflect.Field field = JavaUtil.unwrapJavaObject(self);
            // NOTE: (legacy) JavaField compat - also worked when setting a static value
            final Object target = Modifier.isStatic(field.getModifiers()) ? null : unwrapJavaObject(obj);
            final Object javaValue = convertValueToJava(field, value);
            try {
                field.set(target, javaValue);
            }
            catch (IllegalAccessException e) {
                Helpers.throwException(e); return null;
            }
            return context.nil;
        }

        @JRubyMethod
        public static IRubyObject static_value(final ThreadContext context, final IRubyObject self) {
            final java.lang.reflect.Field field = JavaUtil.unwrapJavaObject(self);
            try {
                return convertJavaToUsableRubyObject(context.runtime, field.get(null));
            }
            catch (IllegalAccessException e) {
                Helpers.throwException(e); return null;
            }
        }

        @JRubyMethod
        public static IRubyObject set_static_value(final ThreadContext context, final IRubyObject self, final IRubyObject value) {
            final java.lang.reflect.Field field = JavaUtil.unwrapJavaObject(self);
            final Object javaValue = convertValueToJava(field, value);
            try {
                field.set(null, javaValue);
            }
            catch (IllegalAccessException e) {
                Helpers.throwException(e); return null;
            }
            return context.nil;
        }

        // JavaUtilities::ModifiedShortcuts :

        @JRubyMethod(name = "public?")
        public static IRubyObject public_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isPublic(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "protected?")
        public static IRubyObject protected_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isProtected(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "private?")
        public static IRubyObject private_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isPrivate(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "final?")
        public static IRubyObject final_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isFinal(self, thiz.getModifiers());
        }

        @JRubyMethod(name = "static?")
        public static IRubyObject static_p(final IRubyObject self) {
            final java.lang.reflect.Field thiz = JavaUtil.unwrapJavaObject(self);
            return isStatic(self, thiz.getModifiers());
        }

    }

    private static Object unwrapJavaObject(final IRubyObject object) {
        return JavaUtil.unwrapJavaValue(object);
    }

    private static Object convertValueToJava(final java.lang.reflect.Field field, IRubyObject value) {
        Object val = value.dataGetStruct();
        if (val instanceof JavaObject) value = (IRubyObject) val;
        return value.toJava(field.getType());
    }

    static RubyBoolean isAbstract(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isAbstract(mod));
    }

    static RubyBoolean isPublic(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isPublic(mod));
    }

    static RubyBoolean isProtected(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isProtected(mod));
    }

    static RubyBoolean isPrivate(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isPrivate(mod));
    }

    static RubyBoolean isFinal(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isFinal(mod));
    }

    static RubyBoolean isStatic(final IRubyObject self, final int mod) {
        return self.getRuntime().newBoolean(java.lang.reflect.Modifier.isStatic(mod));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy