* Eliminate visibility checking for almost all fcall and vcall paths.
[jruby.git] / src / org / jruby / javasupport / proxy / JavaProxyConstructor.java
blob8080e46f1df3bb365848a278a0eb9d6eb1e3c41c
1 /***** BEGIN LICENSE BLOCK *****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Common Public
5 * License Version 1.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.eclipse.org/legal/cpl-v10.html
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
16 * Alternatively, the contents of this file may be used under the terms of
17 * either of the GNU General Public License Version 2 or later (the "GPL"),
18 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the CPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the CPL, the GPL or the LGPL.
27 ***** END LICENSE BLOCK *****/
29 package org.jruby.javasupport.proxy;
31 import java.lang.reflect.Constructor;
32 import java.lang.reflect.InvocationTargetException;
34 import org.jruby.Ruby;
35 import org.jruby.RubyArray;
36 import org.jruby.RubyClass;
37 import org.jruby.RubyFixnum;
38 import org.jruby.RubyModule;
39 import org.jruby.RubyObject;
40 import org.jruby.RubyProc;
41 import org.jruby.anno.JRubyMethod;
42 import org.jruby.exceptions.RaiseException;
43 import org.jruby.internal.runtime.methods.DynamicMethod;
44 import org.jruby.javasupport.Java;
45 import org.jruby.javasupport.JavaObject;
46 import org.jruby.javasupport.JavaUtil;
47 import org.jruby.javasupport.ParameterTypes;
48 import org.jruby.javasupport.util.RuntimeHelpers;
49 import org.jruby.runtime.Arity;
50 import org.jruby.runtime.Block;
51 import org.jruby.runtime.CallType;
52 import org.jruby.runtime.ObjectAllocator;
53 import org.jruby.runtime.builtin.IRubyObject;
55 public class JavaProxyConstructor extends JavaProxyReflectionObject implements ParameterTypes {
57 private final Constructor<?> proxyConstructor;
58 private final Class<?>[] apparentParameterTypes;
60 private final JavaProxyClass declaringProxyClass;
62 JavaProxyConstructor(Ruby runtime, JavaProxyClass pClass,
63 Constructor<?> constructor) {
64 super(runtime, runtime.getJavaSupport().getJavaModule().fastGetClass(
65 "JavaProxyConstructor"));
66 this.declaringProxyClass = pClass;
67 this.proxyConstructor = constructor;
68 Class<?>[] parameterTypes = constructor.getParameterTypes();
69 int len = parameterTypes.length - 1;
70 this.apparentParameterTypes = new Class<?>[len];
71 System.arraycopy(parameterTypes, 0, apparentParameterTypes, 0, len);
74 public Class<?>[] getParameterTypes() {
75 return apparentParameterTypes;
78 public Class<?>[] getExceptionTypes() {
79 return proxyConstructor.getExceptionTypes();
82 public boolean isVarArgs() {
83 return proxyConstructor.isVarArgs();
86 @JRubyMethod(name = "declaring_class")
87 public JavaProxyClass getDeclaringClass() {
88 return declaringProxyClass;
91 public Object newInstance(Object[] args, JavaProxyInvocationHandler handler)
92 throws IllegalArgumentException, InstantiationException,
93 IllegalAccessException, InvocationTargetException {
94 if (args.length != apparentParameterTypes.length) {
95 throw new IllegalArgumentException("wrong number of parameters");
98 Object[] realArgs = new Object[args.length + 1];
99 System.arraycopy(args, 0, realArgs, 0, args.length);
100 realArgs[args.length] = handler;
102 return proxyConstructor.newInstance(realArgs);
105 public static RubyClass createJavaProxyConstructorClass(Ruby runtime,
106 RubyModule javaProxyModule) {
107 RubyClass result = javaProxyModule.defineClassUnder("JavaProxyConstructor",
108 runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
110 JavaProxyReflectionObject.registerRubyMethods(runtime, result);
112 result.defineAnnotatedMethods(JavaProxyConstructor.class);
114 return result;
118 @JRubyMethod
119 public RubyFixnum arity() {
120 return getRuntime().newFixnum(getParameterTypes().length);
123 public boolean equals(Object other) {
124 return other instanceof JavaProxyConstructor &&
125 this.proxyConstructor == ((JavaProxyConstructor)other).proxyConstructor;
128 public int hashCode() {
129 return proxyConstructor.hashCode();
132 protected String nameOnInspection() {
133 return getDeclaringClass().nameOnInspection();
136 public IRubyObject inspect() {
137 StringBuilder result = new StringBuilder();
138 result.append(nameOnInspection());
139 Class<?>[] parameterTypes = getParameterTypes();
140 for (int i = 0; i < parameterTypes.length; i++) {
141 result.append(parameterTypes[i].getName());
142 if (i < parameterTypes.length - 1) {
143 result.append(',');
146 result.append(")>");
147 return getRuntime().newString(result.toString());
150 @JRubyMethod
151 public RubyArray argument_types() {
152 return buildRubyArray(getParameterTypes());
155 @JRubyMethod(frame = true, rest = true)
156 public RubyObject new_instance2(IRubyObject[] args, Block unusedBlock) {
157 Arity.checkArgumentCount(getRuntime(), args, 2, 2);
159 final IRubyObject self = args[0];
160 final Ruby runtime = self.getRuntime();
161 final RubyModule javaUtilities = runtime.getJavaSupport().getJavaUtilitiesModule();
162 RubyArray constructor_args = (RubyArray) args[1];
163 Class<?>[] parameterTypes = getParameterTypes();
164 int count = (int) constructor_args.length().getLongValue();
165 Object[] converted = new Object[count];
167 for (int i = 0; i < count; i++) {
168 // TODO: call ruby method
169 IRubyObject ith = constructor_args.aref(getRuntime().newFixnum(i));
170 converted[i] = JavaUtil.convertArgument(getRuntime(), Java.ruby_to_java(this, ith, Block.NULL_BLOCK), parameterTypes[i]);
173 JavaProxyInvocationHandler handler = new JavaProxyInvocationHandler() {
174 public Object invoke(Object proxy, JavaProxyMethod m, Object[] nargs) throws Throwable {
175 String name = m.getName();
176 DynamicMethod method = self.getMetaClass().searchMethod(name);
177 int v = method.getArity().getValue();
178 IRubyObject[] newArgs = new IRubyObject[nargs.length];
179 for (int i = nargs.length; --i >= 0; ) {
180 newArgs[i] = Java.java_to_ruby(
181 javaUtilities,
182 JavaObject.wrap(runtime, nargs[i]),
183 Block.NULL_BLOCK);
186 if (v < 0 || v == (newArgs.length)) {
187 return JavaUtil.convertRubyToJava(RuntimeHelpers.invoke(runtime.getCurrentContext(), self, name, newArgs, Block.NULL_BLOCK), m.getReturnType());
188 } else {
189 RubyClass superClass = self.getMetaClass().getSuperClass();
190 return JavaUtil.convertRubyToJava(RuntimeHelpers.invokeAs(runtime.getCurrentContext(), superClass, self, name, newArgs, CallType.SUPER, Block.NULL_BLOCK), m.getReturnType());
195 try {
196 return JavaObject.wrap(getRuntime(), newInstance(converted, handler));
197 } catch (Exception e) {
198 RaiseException ex = getRuntime().newArgumentError(
199 "Constructor invocation failed: " + e.getMessage());
200 ex.initCause(e);
201 throw ex;
205 @JRubyMethod(required = 1, optional = 1, frame = true)
206 public RubyObject new_instance(IRubyObject[] args, Block block) {
207 int size = Arity.checkArgumentCount(getRuntime(), args, 1, 2) - 1;
208 final RubyProc proc;
210 // Is there a supplied proc argument or do we assume a block was
211 // supplied
212 if (args[size] instanceof RubyProc) {
213 proc = (RubyProc) args[size];
214 } else {
215 proc = getRuntime().newProc(Block.Type.PROC,block);
216 size++;
219 RubyArray constructor_args = (RubyArray) args[0];
220 Class<?>[] parameterTypes = getParameterTypes();
222 int count = (int) constructor_args.length().getLongValue();
223 Object[] converted = new Object[count];
224 for (int i = 0; i < count; i++) {
225 // TODO: call ruby method
226 IRubyObject ith = constructor_args.aref(getRuntime().newFixnum(i));
227 converted[i] = JavaUtil.convertArgument(getRuntime(), Java.ruby_to_java(this, ith, Block.NULL_BLOCK), parameterTypes[i]);
230 final IRubyObject recv = this;
232 JavaProxyInvocationHandler handler = new JavaProxyInvocationHandler() {
234 public Object invoke(Object proxy, JavaProxyMethod method,
235 Object[] nargs) throws Throwable {
236 int length = nargs == null ? 0 : nargs.length;
237 IRubyObject[] rubyArgs = new IRubyObject[length + 2];
238 rubyArgs[0] = JavaObject.wrap(recv.getRuntime(), proxy);
239 rubyArgs[1] = method;
240 for (int i = 0; i < length; i++) {
241 rubyArgs[i + 2] = JavaUtil.convertJavaToRuby(getRuntime(),
242 nargs[i]);
244 IRubyObject call_result = proc.call(getRuntime().getCurrentContext(), rubyArgs);
245 Object converted_result = JavaUtil.convertRubyToJava(
246 call_result, method.getReturnType());
247 return converted_result;
252 Object result;
253 try {
254 result = newInstance(converted, handler);
255 } catch (Exception e) {
256 RaiseException ex = getRuntime().newArgumentError(
257 "Constructor invocation failed: " + e.getMessage());
258 ex.initCause(e);
259 throw ex;
262 return JavaObject.wrap(getRuntime(), result);