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);
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) {
147 return getRuntime().newString(result
.toString());
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(
182 JavaObject
.wrap(runtime
, nargs
[i
]),
186 if (v
< 0 || v
== (newArgs
.length
)) {
187 return JavaUtil
.convertRubyToJava(RuntimeHelpers
.invoke(runtime
.getCurrentContext(), self
, name
, newArgs
), m
.getReturnType());
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());
196 return JavaObject
.wrap(getRuntime(), newInstance(converted
, handler
));
197 } catch (Exception e
) {
198 RaiseException ex
= getRuntime().newArgumentError(
199 "Constructor invocation failed: " + e
.getMessage());
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;
210 // Is there a supplied proc argument or do we assume a block was
212 if (args
[size
] instanceof RubyProc
) {
213 proc
= (RubyProc
) args
[size
];
215 proc
= getRuntime().newProc(Block
.Type
.PROC
,block
);
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(),
244 IRubyObject call_result
= proc
.call(getRuntime().getCurrentContext(), rubyArgs
);
245 Object converted_result
= JavaUtil
.convertRubyToJava(
246 call_result
, method
.getReturnType());
247 return converted_result
;
254 result
= newInstance(converted
, handler
);
255 } catch (Exception e
) {
256 RaiseException ex
= getRuntime().newArgumentError(
257 "Constructor invocation failed: " + e
.getMessage());
262 return JavaObject
.wrap(getRuntime(), result
);