1 37 package org.jruby.javasupport; 38 39 import java.lang.reflect.AccessibleObject ; 40 import java.lang.reflect.InvocationTargetException ; 41 import java.lang.reflect.Method ; 42 import java.lang.reflect.Modifier ; 43 44 import org.jruby.Ruby; 45 import org.jruby.RubyBoolean; 46 import org.jruby.RubyClass; 47 import org.jruby.RubyModule; 48 import org.jruby.RubyString; 49 import org.jruby.exceptions.RaiseException; 50 import org.jruby.javasupport.proxy.InternalJavaProxy; 51 import org.jruby.javasupport.proxy.JavaProxyClass; 52 import org.jruby.javasupport.proxy.JavaProxyMethod; 53 import org.jruby.runtime.CallbackFactory; 54 import org.jruby.runtime.ObjectAllocator; 55 import org.jruby.runtime.builtin.IRubyObject; 56 57 public class JavaMethod extends JavaCallable { 58 private final Method method; 59 60 public static RubyClass createJavaMethodClass(Ruby runtime, RubyModule javaModule) { 61 RubyClass result = 64 javaModule.defineClassUnder("JavaMethod", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); 65 CallbackFactory callbackFactory = runtime.callbackFactory(JavaMethod.class); 66 67 JavaAccessibleObject.registerRubyMethods(runtime, result); 68 69 result.defineFastMethod("name", callbackFactory.getFastMethod("name")); 70 result.defineFastMethod("arity", callbackFactory.getFastMethod("arity")); 71 result.defineFastMethod("public?", callbackFactory.getFastMethod("public_p")); 72 result.defineFastMethod("final?", callbackFactory.getFastMethod("final_p")); 73 result.defineFastMethod("static?", callbackFactory.getFastMethod("static_p")); 74 result.defineFastMethod("invoke", callbackFactory.getFastOptMethod("invoke")); 75 result.defineFastMethod("invoke_static", callbackFactory.getFastOptMethod("invoke_static")); 76 result.defineFastMethod("argument_types", callbackFactory.getFastMethod("argument_types")); 77 result.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect")); 78 result.defineFastMethod("return_type", callbackFactory.getFastMethod("return_type")); 79 80 return result; 81 } 82 83 public JavaMethod(Ruby runtime, Method method) { 84 super(runtime, (RubyClass) runtime.getModule("Java").getClass("JavaMethod")); 85 this.method = method; 86 87 if (Modifier.isPublic(method.getModifiers()) && 91 Modifier.isPublic(method.getClass().getModifiers()) && 92 !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { 93 accesibleObject().setAccessible(true); 94 } 95 } 96 97 public static JavaMethod create(Ruby runtime, Method method) { 98 return new JavaMethod(runtime, method); 99 } 100 101 public static JavaMethod create(Ruby runtime, Class javaClass, String methodName, Class [] argumentTypes) { 102 try { 103 Method method = javaClass.getMethod(methodName, argumentTypes); 104 return create(runtime, method); 105 } catch (NoSuchMethodException e) { 106 throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'", 107 methodName); 108 } 109 } 110 111 public static JavaMethod createDeclared(Ruby runtime, Class javaClass, String methodName, Class [] argumentTypes) { 112 try { 113 Method method = javaClass.getDeclaredMethod(methodName, argumentTypes); 114 return create(runtime, method); 115 } catch (NoSuchMethodException e) { 116 throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'", 117 methodName); 118 } 119 } 120 121 public RubyString name() { 122 return getRuntime().newString(method.getName()); 123 } 124 125 protected int getArity() { 126 return method.getParameterTypes().length; 127 } 128 129 public RubyBoolean public_p() { 130 return getRuntime().newBoolean(Modifier.isPublic(method.getModifiers())); 131 } 132 133 public RubyBoolean final_p() { 134 return getRuntime().newBoolean(Modifier.isFinal(method.getModifiers())); 135 } 136 137 public IRubyObject invoke(IRubyObject[] args) { 138 if (args.length != 1 + getArity()) { 139 throw getRuntime().newArgumentError(args.length, 1 + getArity()); 140 } 141 142 IRubyObject invokee = args[0]; 143 if (! (invokee instanceof JavaObject)) { 144 throw getRuntime().newTypeError("invokee not a java object"); 145 } 146 Object javaInvokee = ((JavaObject) invokee).getValue(); 147 Object [] arguments = new Object [args.length - 1]; 148 System.arraycopy(args, 1, arguments, 0, arguments.length); 149 convertArguments(arguments); 150 151 if (! method.getDeclaringClass().isInstance(javaInvokee)) { 152 throw getRuntime().newTypeError("invokee not instance of method's class (" + 153 "got" + javaInvokee.getClass().getName() + " wanted " + 154 method.getDeclaringClass().getName() + ")"); 155 } 156 157 if (javaInvokee instanceof InternalJavaProxy) { 161 JavaProxyClass jpc = ((InternalJavaProxy) javaInvokee) 162 .___getProxyClass(); 163 JavaProxyMethod jpm; 164 try { 165 jpm = jpc.getMethod(method.getName(), method 166 .getParameterTypes()); 167 } catch (NoSuchMethodException e) { 168 RaiseException err = getRuntime().newTypeError( 169 "mismatch with proxy/super method?"); 170 err.initCause(e); 171 throw err; 172 } 173 if (jpm.hasSuperImplementation()) { 174 return invokeWithExceptionHandling(jpm.getSuperMethod(), 175 javaInvokee, arguments); 176 } 177 178 } 179 180 return invokeWithExceptionHandling(method, javaInvokee, arguments); 181 } 182 183 public IRubyObject invoke_static(IRubyObject[] args) { 184 if (args.length != getArity()) { 185 throw getRuntime().newArgumentError(args.length, getArity()); 186 } 187 Object [] arguments = new Object [args.length]; 188 System.arraycopy(args, 0, arguments, 0, arguments.length); 189 convertArguments(arguments); 190 return invokeWithExceptionHandling(method, null, arguments); 191 } 192 193 public IRubyObject return_type() { 194 Class klass = method.getReturnType(); 195 196 if (klass.equals(void.class)) { 197 return getRuntime().getNil(); 198 } 199 return JavaClass.get(getRuntime(), klass); 200 } 201 202 private IRubyObject invokeWithExceptionHandling(Method method, Object javaInvokee, Object [] arguments) { 203 try { 204 Object result = method.invoke(javaInvokee, arguments); 205 return JavaObject.wrap(getRuntime(), result); 206 } catch (IllegalArgumentException iae) { 207 throw getRuntime().newTypeError("expected " + argument_types().inspect()); 208 } catch (IllegalAccessException iae) { 209 throw getRuntime().newTypeError("illegal access on '" + method.getName() + "': " + iae.getMessage()); 210 } catch (InvocationTargetException ite) { 211 getRuntime().getJavaSupport().handleNativeException(ite.getTargetException()); 212 return getRuntime().getNil(); 214 } 215 } 216 217 private void convertArguments(Object [] arguments) { 218 Class [] parameterTypes = parameterTypes(); 219 for (int i = 0; i < arguments.length; i++) { 220 arguments[i] = JavaUtil.convertArgument(arguments[i], parameterTypes[i]); 221 } 222 } 223 224 protected Class [] parameterTypes() { 225 return method.getParameterTypes(); 226 } 227 228 protected String nameOnInspection() { 229 return "#<" + getType().toString() + "/" + method.getName() + "("; 230 } 231 232 public RubyBoolean static_p() { 233 return getRuntime().newBoolean(isStatic()); 234 } 235 236 private boolean isStatic() { 237 return Modifier.isStatic(method.getModifiers()); 238 } 239 240 protected int getModifiers() { 241 return method.getModifiers(); 242 } 243 244 protected AccessibleObject accesibleObject() { 245 return method; 246 } 247 } 248 | Popular Tags |