Fix for JRUBY-2882. Handle error messages related to constructors better
[jruby.git] / src / org / jruby / javasupport / JavaUtil.java
blob3dc319d4d8892f49e0ab325e60ec12dc95331ed9
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) 2001 Alan Moore <alan_moore@gmx.net>
15 * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16 * Copyright (C) 2002 Anders Bengtsson <ndrsbngtssn@yahoo.se>
17 * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
18 * Copyright (C) 2002 Don Schwartz <schwardo@users.sourceforge.net>
19 * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
20 * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
22 * Alternatively, the contents of this file may be used under the terms of
23 * either of the GNU General Public License Version 2 or later (the "GPL"),
24 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25 * in which case the provisions of the GPL or the LGPL are applicable instead
26 * of those above. If you wish to allow use of your version of this file only
27 * under the terms of either the GPL or the LGPL, and not to allow others to
28 * use your version of this file under the terms of the CPL, indicate your
29 * decision by deleting the provisions above and replace them with the notice
30 * and other provisions required by the GPL or the LGPL. If you do not delete
31 * the provisions above, a recipient may use your version of this file under
32 * the terms of any one of the CPL, the GPL or the LGPL.
33 ***** END LICENSE BLOCK *****/
34 package org.jruby.javasupport;
36 import java.io.UnsupportedEncodingException;
37 import java.lang.reflect.Method;
38 import java.math.BigDecimal;
39 import java.math.BigInteger;
40 import java.util.HashMap;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.Map;
45 import java.util.Set;
46 import java.util.regex.Matcher;
47 import java.util.regex.Pattern;
48 import org.jruby.Ruby;
49 import org.jruby.RubyBignum;
50 import org.jruby.RubyBoolean;
51 import org.jruby.RubyClass;
52 import org.jruby.RubyFixnum;
53 import org.jruby.RubyFloat;
54 import org.jruby.RubyInteger;
55 import org.jruby.RubyModule;
56 import org.jruby.RubyNil;
57 import org.jruby.RubyNumeric;
58 import org.jruby.RubyObject;
59 import org.jruby.RubyProc;
60 import org.jruby.RubyString;
61 import org.jruby.RubyTime;
62 import org.jruby.internal.runtime.methods.CallConfiguration;
63 import org.jruby.internal.runtime.methods.DynamicMethod;
64 import org.jruby.java.proxies.JavaProxy;
65 import org.jruby.javasupport.util.RuntimeHelpers;
66 import org.jruby.runtime.Block;
67 import org.jruby.runtime.ClassIndex;
68 import org.jruby.runtime.MethodIndex;
69 import org.jruby.runtime.ThreadContext;
70 import org.jruby.runtime.Visibility;
71 import org.jruby.runtime.builtin.IRubyObject;
73 import org.jruby.util.ByteList;
75 public class JavaUtil {
77 public static Object convertRubyToJava(IRubyObject rubyObject) {
78 return convertRubyToJava(rubyObject, Object.class);
81 public interface RubyConverter {
82 public Object convert(ThreadContext context, IRubyObject rubyObject);
85 public static final RubyConverter RUBY_BOOLEAN_CONVERTER = new RubyConverter() {
86 public Object convert(ThreadContext context, IRubyObject rubyObject) {
87 return Boolean.valueOf(rubyObject.isTrue());
91 public static final RubyConverter RUBY_BYTE_CONVERTER = new RubyConverter() {
92 public Object convert(ThreadContext context, IRubyObject rubyObject) {
93 if (rubyObject.respondsTo("to_i")) {
94 return new Byte((byte) ((RubyNumeric) rubyObject.callMethod(
95 context, MethodIndex.TO_I, "to_i")).getLongValue());
97 return new Byte((byte) 0);
101 public static final RubyConverter RUBY_SHORT_CONVERTER = new RubyConverter() {
102 public Object convert(ThreadContext context, IRubyObject rubyObject) {
103 if (rubyObject.respondsTo("to_i")) {
104 return new Short((short) ((RubyNumeric) rubyObject.callMethod(
105 context, MethodIndex.TO_I, "to_i")).getLongValue());
107 return new Short((short) 0);
111 public static final RubyConverter RUBY_CHAR_CONVERTER = new RubyConverter() {
112 public Object convert(ThreadContext context, IRubyObject rubyObject) {
113 if (rubyObject.respondsTo("to_i")) {
114 return new Character((char) ((RubyNumeric) rubyObject.callMethod(
115 context, MethodIndex.TO_I, "to_i")).getLongValue());
117 return new Character((char) 0);
121 public static final RubyConverter RUBY_INTEGER_CONVERTER = new RubyConverter() {
122 public Object convert(ThreadContext context, IRubyObject rubyObject) {
123 if (rubyObject.respondsTo("to_i")) {
124 return new Integer((int) ((RubyNumeric) rubyObject.callMethod(
125 context, MethodIndex.TO_I, "to_i")).getLongValue());
127 return new Integer(0);
131 public static final RubyConverter RUBY_LONG_CONVERTER = new RubyConverter() {
132 public Object convert(ThreadContext context, IRubyObject rubyObject) {
133 if (rubyObject.respondsTo("to_i")) {
134 return new Long(((RubyNumeric) rubyObject.callMethod(
135 context, MethodIndex.TO_I, "to_i")).getLongValue());
137 return new Long(0);
141 public static final RubyConverter RUBY_FLOAT_CONVERTER = new RubyConverter() {
142 public Object convert(ThreadContext context, IRubyObject rubyObject) {
143 if (rubyObject.respondsTo("to_f")) {
144 return new Float((float) ((RubyNumeric) rubyObject.callMethod(
145 context, MethodIndex.TO_F, "to_f")).getDoubleValue());
147 return new Float(0.0);
151 public static final RubyConverter RUBY_DOUBLE_CONVERTER = new RubyConverter() {
152 public Object convert(ThreadContext context, IRubyObject rubyObject) {
153 if (rubyObject.respondsTo("to_f")) {
154 return new Double(((RubyNumeric) rubyObject.callMethod(
155 context, MethodIndex.TO_F, "to_f")).getDoubleValue());
157 return new Double(0.0);
161 public static final RubyConverter ARRAY_BOOLEAN_CONVERTER = new RubyConverter() {
162 public Object convert(ThreadContext context, IRubyObject rubyObject) {
163 if (rubyObject == context.getRuntime().getFalse() || rubyObject.isNil()) {
164 return Boolean.FALSE;
165 } else if (rubyObject == context.getRuntime().getTrue()) {
166 return Boolean.TRUE;
167 } else if (rubyObject instanceof RubyNumeric) {
168 return ((RubyNumeric)rubyObject).getLongValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
169 } else if (rubyObject instanceof RubyString) {
170 return Boolean.valueOf(rubyObject.asJavaString());
171 } else if (rubyObject instanceof JavaProxy) {
172 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
173 } else if (rubyObject.respondsTo("to_i")) {
174 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
175 return integer.getLongValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
176 } else {
177 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
182 public static final RubyConverter ARRAY_BYTE_CONVERTER = new RubyConverter() {
183 public Object convert(ThreadContext context, IRubyObject rubyObject) {
184 if (rubyObject instanceof RubyNumeric) {
185 return Byte.valueOf((byte)((RubyNumeric)rubyObject).getLongValue());
186 } else if (rubyObject instanceof RubyString) {
187 return Byte.valueOf(rubyObject.asJavaString());
188 } else if (rubyObject instanceof JavaProxy) {
189 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
190 } else if (rubyObject.respondsTo("to_i")) {
191 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
192 return Byte.valueOf((byte)integer.getLongValue());
193 } else {
194 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
199 public static final RubyConverter ARRAY_SHORT_CONVERTER = new RubyConverter() {
200 public Object convert(ThreadContext context, IRubyObject rubyObject) {
201 if (rubyObject instanceof RubyNumeric) {
202 return Short.valueOf((short)((RubyNumeric)rubyObject).getLongValue());
203 } else if (rubyObject instanceof RubyString) {
204 return Short.valueOf(rubyObject.asJavaString());
205 } else if (rubyObject instanceof JavaProxy) {
206 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
207 } else if (rubyObject.respondsTo("to_i")) {
208 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
209 return Short.valueOf((short)integer.getLongValue());
210 } else {
211 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
216 public static final RubyConverter ARRAY_CHAR_CONVERTER = new RubyConverter() {
217 public Object convert(ThreadContext context, IRubyObject rubyObject) {
218 if (rubyObject instanceof RubyNumeric) {
219 return Character.valueOf((char)((RubyNumeric)rubyObject).getLongValue());
220 } else if (rubyObject instanceof RubyString) {
221 return Character.valueOf(rubyObject.asJavaString().charAt(0));
222 } else if (rubyObject instanceof JavaProxy) {
223 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
224 } else if (rubyObject.respondsTo("to_i")) {
225 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
226 return Character.valueOf((char)integer.getLongValue());
227 } else {
228 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
233 public static final RubyConverter ARRAY_INT_CONVERTER = new RubyConverter() {
234 public Object convert(ThreadContext context, IRubyObject rubyObject) {
235 if (rubyObject instanceof RubyNumeric) {
236 return Integer.valueOf((int)((RubyNumeric)rubyObject).getLongValue());
237 } else if (rubyObject instanceof RubyString) {
238 return Integer.valueOf(rubyObject.asJavaString());
239 } else if (rubyObject instanceof JavaProxy) {
240 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
241 } else if (rubyObject.respondsTo("to_i")) {
242 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
243 return Integer.valueOf((int)integer.getLongValue());
244 } else {
245 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
250 public static final RubyConverter ARRAY_LONG_CONVERTER = new RubyConverter() {
251 public Object convert(ThreadContext context, IRubyObject rubyObject) {
252 if (rubyObject instanceof RubyNumeric) {
253 return Long.valueOf(((RubyNumeric)rubyObject).getLongValue());
254 } else if (rubyObject instanceof RubyString) {
255 return Long.valueOf(rubyObject.asJavaString());
256 } else if (rubyObject instanceof JavaProxy) {
257 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
258 } else if (rubyObject.respondsTo("to_i")) {
259 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
260 return Long.valueOf(integer.getLongValue());
261 } else {
262 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
267 public static final RubyConverter ARRAY_FLOAT_CONVERTER = new RubyConverter() {
268 public Object convert(ThreadContext context, IRubyObject rubyObject) {
269 if (rubyObject instanceof RubyNumeric) {
270 return Float.valueOf((float)((RubyNumeric)rubyObject).getDoubleValue());
271 } else if (rubyObject instanceof RubyString) {
272 return Float.valueOf(rubyObject.asJavaString());
273 } else if (rubyObject instanceof JavaProxy) {
274 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
275 } else if (rubyObject.respondsTo("to_i")) {
276 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
277 return Float.valueOf((float)integer.getDoubleValue());
278 } else {
279 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
284 public static final RubyConverter ARRAY_DOUBLE_CONVERTER = new RubyConverter() {
285 public Object convert(ThreadContext context, IRubyObject rubyObject) {
286 if (rubyObject instanceof RubyNumeric) {
287 return Double.valueOf(((RubyNumeric)rubyObject).getDoubleValue());
288 } else if (rubyObject instanceof RubyString) {
289 return Double.valueOf(rubyObject.asJavaString());
290 } else if (rubyObject instanceof JavaProxy) {
291 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
292 } else if (rubyObject.respondsTo("to_i")) {
293 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
294 return Double.valueOf(integer.getDoubleValue());
295 } else {
296 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
301 public static final RubyConverter ARRAY_OBJECT_CONVERTER = new RubyConverter() {
302 public Object convert(ThreadContext context, IRubyObject rubyObject) {
303 if (rubyObject instanceof RubyInteger) {
304 long value = ((RubyInteger)rubyObject).getLongValue();
305 if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
306 return Integer.valueOf((int)value);
307 } else if (value >= Long.MIN_VALUE && value <= Long.MAX_VALUE) {
308 return Long.valueOf(value);
309 } else {
310 return new BigInteger(rubyObject.toString());
312 } else if (rubyObject instanceof RubyFloat) {
313 return Double.valueOf(((RubyFloat)rubyObject).getDoubleValue());
314 } else if (rubyObject instanceof JavaProxy) {
315 return ((JavaProxy)rubyObject).unwrap();
316 } else {
317 return java_to_ruby(context.getRuntime(), rubyObject);
322 public static final RubyConverter ARRAY_CLASS_CONVERTER = new RubyConverter() {
323 public Object convert(ThreadContext context, IRubyObject rubyObject) {
324 if (rubyObject instanceof JavaClass) {
325 return ((JavaClass)rubyObject).javaClass();
326 } else {
327 return java_to_ruby(context.getRuntime(), rubyObject);
332 public static final RubyConverter ARRAY_STRING_CONVERTER = new RubyConverter() {
333 public Object convert(ThreadContext context, IRubyObject rubyObject) {
334 if (rubyObject instanceof RubyString) {
335 return ((RubyString)rubyObject).getUnicodeValue();
336 } else {
337 return rubyObject.toString();
342 public static final RubyConverter ARRAY_BIGINTEGER_CONVERTER = new RubyConverter() {
343 public Object convert(ThreadContext context, IRubyObject rubyObject) {
344 if (rubyObject instanceof RubyNumeric) {
345 return BigInteger.valueOf(((RubyNumeric)rubyObject).getLongValue());
346 } else if (rubyObject instanceof RubyString) {
347 return new BigDecimal(rubyObject.asJavaString());
348 } else if (rubyObject instanceof JavaProxy) {
349 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
350 } else if (rubyObject.respondsTo("to_i")) {
351 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
352 return BigInteger.valueOf(integer.getLongValue());
353 } else {
354 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
359 public static final RubyConverter ARRAY_BIGDECIMAL_CONVERTER = new RubyConverter() {
360 public Object convert(ThreadContext context, IRubyObject rubyObject) {
361 if (rubyObject instanceof RubyNumeric) {
362 return BigDecimal.valueOf(((RubyNumeric)rubyObject).getDoubleValue());
363 } else if (rubyObject instanceof RubyString) {
364 return new BigDecimal(rubyObject.asJavaString());
365 } else if (rubyObject instanceof JavaProxy) {
366 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
367 } else if (rubyObject.respondsTo("to_f")) {
368 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_f");
369 return BigDecimal.valueOf(integer.getDoubleValue());
370 } else if (rubyObject.respondsTo("to_i")) {
371 RubyInteger integer = (RubyInteger)RuntimeHelpers.invoke(context, rubyObject, "to_i");
372 return BigDecimal.valueOf(integer.getLongValue());
373 } else {
374 return ruby_to_java(rubyObject, rubyObject, Block.NULL_BLOCK);
379 public static final Map<Class, RubyConverter> RUBY_CONVERTERS = new HashMap<Class, RubyConverter>();
380 public static final Map<Class, RubyConverter> ARRAY_CONVERTERS = new HashMap<Class, RubyConverter>();
382 static {
383 RUBY_CONVERTERS.put(Boolean.class, RUBY_BOOLEAN_CONVERTER);
384 RUBY_CONVERTERS.put(Boolean.TYPE, RUBY_BOOLEAN_CONVERTER);
385 RUBY_CONVERTERS.put(Byte.class, RUBY_BYTE_CONVERTER);
386 RUBY_CONVERTERS.put(Byte.TYPE, RUBY_BYTE_CONVERTER);
387 RUBY_CONVERTERS.put(Short.class, RUBY_SHORT_CONVERTER);
388 RUBY_CONVERTERS.put(Short.TYPE, RUBY_SHORT_CONVERTER);
389 RUBY_CONVERTERS.put(Integer.class, RUBY_INTEGER_CONVERTER);
390 RUBY_CONVERTERS.put(Integer.TYPE, RUBY_INTEGER_CONVERTER);
391 RUBY_CONVERTERS.put(Long.class, RUBY_LONG_CONVERTER);
392 RUBY_CONVERTERS.put(Long.TYPE, RUBY_LONG_CONVERTER);
393 RUBY_CONVERTERS.put(Float.class, RUBY_FLOAT_CONVERTER);
394 RUBY_CONVERTERS.put(Float.TYPE, RUBY_FLOAT_CONVERTER);
395 RUBY_CONVERTERS.put(Double.class, RUBY_DOUBLE_CONVERTER);
396 RUBY_CONVERTERS.put(Double.TYPE, RUBY_DOUBLE_CONVERTER);
398 ARRAY_CONVERTERS.put(Boolean.class, ARRAY_BOOLEAN_CONVERTER);
399 ARRAY_CONVERTERS.put(Boolean.TYPE, ARRAY_BOOLEAN_CONVERTER);
400 ARRAY_CONVERTERS.put(Byte.class, ARRAY_BYTE_CONVERTER);
401 ARRAY_CONVERTERS.put(Byte.TYPE, ARRAY_BYTE_CONVERTER);
402 ARRAY_CONVERTERS.put(Short.class, ARRAY_SHORT_CONVERTER);
403 ARRAY_CONVERTERS.put(Short.TYPE, ARRAY_SHORT_CONVERTER);
404 ARRAY_CONVERTERS.put(Character.class, ARRAY_CHAR_CONVERTER);
405 ARRAY_CONVERTERS.put(Character.TYPE, ARRAY_CHAR_CONVERTER);
406 ARRAY_CONVERTERS.put(Integer.class, ARRAY_INT_CONVERTER);
407 ARRAY_CONVERTERS.put(Integer.TYPE, ARRAY_INT_CONVERTER);
408 ARRAY_CONVERTERS.put(Long.class, ARRAY_LONG_CONVERTER);
409 ARRAY_CONVERTERS.put(Long.TYPE, ARRAY_LONG_CONVERTER);
410 ARRAY_CONVERTERS.put(Float.class, ARRAY_FLOAT_CONVERTER);
411 ARRAY_CONVERTERS.put(Float.TYPE, ARRAY_FLOAT_CONVERTER);
412 ARRAY_CONVERTERS.put(Double.class, ARRAY_DOUBLE_CONVERTER);
413 ARRAY_CONVERTERS.put(Double.TYPE, ARRAY_DOUBLE_CONVERTER);
414 ARRAY_CONVERTERS.put(String.class, ARRAY_STRING_CONVERTER);
415 ARRAY_CONVERTERS.put(Class.class, ARRAY_CLASS_CONVERTER);
416 ARRAY_CONVERTERS.put(BigInteger.class, ARRAY_BIGINTEGER_CONVERTER);
417 ARRAY_CONVERTERS.put(BigDecimal.class, ARRAY_BIGDECIMAL_CONVERTER);
420 public static RubyConverter getArrayConverter(Class type) {
421 RubyConverter converter = ARRAY_CONVERTERS.get(type);
422 if (converter == null) {
423 return ARRAY_OBJECT_CONVERTER;
425 return converter;
428 public static byte convertRubyToJavaByte(IRubyObject rubyObject) {
429 return ((Byte)convertRubyToJava(rubyObject, byte.class)).byteValue();
432 public static short convertRubyToJavaShort(IRubyObject rubyObject) {
433 return ((Short)convertRubyToJava(rubyObject, short.class)).shortValue();
436 public static char convertRubyToJavaChar(IRubyObject rubyObject) {
437 return ((Character)convertRubyToJava(rubyObject, char.class)).charValue();
440 public static int convertRubyToJavaInt(IRubyObject rubyObject) {
441 return ((Integer)convertRubyToJava(rubyObject, int.class)).intValue();
444 public static long convertRubyToJavaLong(IRubyObject rubyObject) {
445 return ((Long)convertRubyToJava(rubyObject, long.class)).longValue();
448 public static float convertRubyToJavaFloat(IRubyObject rubyObject) {
449 return ((Float)convertRubyToJava(rubyObject, float.class)).floatValue();
452 public static double convertRubyToJavaDouble(IRubyObject rubyObject) {
453 return ((Double)convertRubyToJava(rubyObject, double.class)).doubleValue();
456 public static boolean convertRubyToJavaBoolean(IRubyObject rubyObject) {
457 return ((Boolean)convertRubyToJava(rubyObject, boolean.class)).booleanValue();
460 public static Object convertRubyToJava(IRubyObject rubyObject, Class javaClass) {
461 if (javaClass == void.class || rubyObject == null || rubyObject.isNil()) {
462 return null;
465 ThreadContext context = rubyObject.getRuntime().getCurrentContext();
467 if (rubyObject.respondsTo("java_object")) {
468 rubyObject = rubyObject.callMethod(context, "java_object");
471 if (rubyObject.respondsTo("to_java_object")) {
472 rubyObject = rubyObject.callMethod(context, "to_java_object");
475 if (rubyObject instanceof JavaObject) {
476 Object value = ((JavaObject) rubyObject).getValue();
478 return convertArgument(rubyObject.getRuntime(), value, value.getClass());
480 } else if (javaClass == Object.class || javaClass == null) {
481 /* The Java method doesn't care what class it is, but we need to
482 know what to convert it to, so we use the object's own class.
483 If that doesn't help, we use String to force a call to the
484 object's "to_s" method. */
485 javaClass = rubyObject.getJavaClass();
488 if (javaClass.isInstance(rubyObject)) {
489 // rubyObject is already of the required jruby class (or subclass)
490 return rubyObject;
493 if (javaClass.isPrimitive()) {
494 RubyConverter converter = RUBY_CONVERTERS.get(javaClass);
495 if (converter != null) {
496 return converter.convert(context, rubyObject);
499 // XXX this probably isn't good enough -AM
500 String s = ((RubyString) rubyObject.callMethod(context, MethodIndex.TO_S, "to_s")).toString();
501 if (s.length() > 0) {
502 return new Character(s.charAt(0));
504 return new Character('\0');
505 } else if (javaClass == String.class) {
506 RubyString rubyString = (RubyString) rubyObject.callMethod(context, MethodIndex.TO_S, "to_s");
507 ByteList bytes = rubyString.getByteList();
508 try {
509 return new String(bytes.unsafeBytes(), bytes.begin(), bytes.length(), "UTF8");
510 } catch (UnsupportedEncodingException uee) {
511 return new String(bytes.unsafeBytes(), bytes.begin(), bytes.length());
513 } else if (javaClass == ByteList.class) {
514 return rubyObject.convertToString().getByteList();
515 } else if (javaClass == BigInteger.class) {
516 if (rubyObject instanceof RubyBignum) {
517 return ((RubyBignum)rubyObject).getValue();
518 } else if (rubyObject instanceof RubyNumeric) {
519 return BigInteger.valueOf (((RubyNumeric)rubyObject).getLongValue());
520 } else if (rubyObject.respondsTo("to_i")) {
521 RubyNumeric rubyNumeric = ((RubyNumeric)rubyObject.callMethod(context,MethodIndex.TO_F, "to_f"));
522 return BigInteger.valueOf (rubyNumeric.getLongValue());
524 } else if (javaClass == BigDecimal.class && !(rubyObject instanceof JavaObject)) {
525 if (rubyObject.respondsTo("to_f")) {
526 double double_value = ((RubyNumeric)rubyObject.callMethod(context,MethodIndex.TO_F, "to_f")).getDoubleValue();
527 return new BigDecimal(double_value);
530 try {
531 return ((JavaObject) rubyObject).getValue();
532 } catch (ClassCastException ex) {
533 if (rubyObject.getRuntime().getDebug().isTrue()) ex.printStackTrace();
534 return null;
538 public static IRubyObject[] convertJavaArrayToRuby(Ruby runtime, Object[] objects) {
539 if (objects == null) return IRubyObject.NULL_ARRAY;
541 IRubyObject[] rubyObjects = new IRubyObject[objects.length];
542 for (int i = 0; i < objects.length; i++) {
543 rubyObjects[i] = convertJavaToRuby(runtime, objects[i]);
545 return rubyObjects;
548 public interface JavaConverter {
549 public IRubyObject convert(Ruby runtime, Object object);
552 public static final JavaConverter JAVA_DEFAULT_CONVERTER = new JavaConverter() {
553 public IRubyObject convert(Ruby runtime, Object object) {
554 if (object == null) {
555 return runtime.getNil();
558 if (object instanceof IRubyObject) {
559 return (IRubyObject) object;
562 // Note: returns JavaObject instance, which is not
563 // directly usable. probably too late to change this now,
564 // supplying alternate method convertJavaToUsableRubyObject
565 return JavaObject.wrap(runtime, object);
569 public static final JavaConverter JAVA_BOOLEAN_CONVERTER = new JavaConverter() {
570 public IRubyObject convert(Ruby runtime, Object object) {
571 if (object == null) return runtime.getNil();
572 return RubyBoolean.newBoolean(runtime, ((Boolean)object).booleanValue());
576 public static final JavaConverter JAVA_FLOAT_CONVERTER = new JavaConverter() {
577 public IRubyObject convert(Ruby runtime, Object object) {
578 if (object == null) return runtime.getNil();
579 return RubyFloat.newFloat(runtime, ((Float)object).doubleValue());
583 public static final JavaConverter JAVA_DOUBLE_CONVERTER = new JavaConverter() {
584 public IRubyObject convert(Ruby runtime, Object object) {
585 if (object == null) return runtime.getNil();
586 return RubyFloat.newFloat(runtime, ((Double)object).doubleValue());
590 public static final JavaConverter JAVA_CHAR_CONVERTER = new JavaConverter() {
591 public IRubyObject convert(Ruby runtime, Object object) {
592 if (object == null) return runtime.getNil();
593 return RubyFixnum.newFixnum(runtime, ((Character)object).charValue());
597 public static final JavaConverter JAVA_BYTE_CONVERTER = new JavaConverter() {
598 public IRubyObject convert(Ruby runtime, Object object) {
599 if (object == null) return runtime.getNil();
600 return RubyFixnum.newFixnum(runtime, ((Byte)object).byteValue());
604 public static final JavaConverter JAVA_SHORT_CONVERTER = new JavaConverter() {
605 public IRubyObject convert(Ruby runtime, Object object) {
606 if (object == null) return runtime.getNil();
607 return RubyFixnum.newFixnum(runtime, ((Short)object).shortValue());
611 public static final JavaConverter JAVA_INT_CONVERTER = new JavaConverter() {
612 public IRubyObject convert(Ruby runtime, Object object) {
613 if (object == null) return runtime.getNil();
614 return RubyFixnum.newFixnum(runtime, ((Integer)object).intValue());
618 public static final JavaConverter JAVA_LONG_CONVERTER = new JavaConverter() {
619 public IRubyObject convert(Ruby runtime, Object object) {
620 if (object == null) return runtime.getNil();
621 return RubyFixnum.newFixnum(runtime, ((Long)object).longValue());
625 public static final JavaConverter JAVA_STRING_CONVERTER = new JavaConverter() {
626 public IRubyObject convert(Ruby runtime, Object object) {
627 if (object == null) return runtime.getNil();
628 return RubyString.newUnicodeString(runtime, (String)object);
632 public static final JavaConverter BYTELIST_CONVERTER = new JavaConverter() {
633 public IRubyObject convert(Ruby runtime, Object object) {
634 if (object == null) return runtime.getNil();
635 return RubyString.newString(runtime, (ByteList)object);
639 public static final JavaConverter JAVA_BIGINTEGER_CONVERTER = new JavaConverter() {
640 public IRubyObject convert(Ruby runtime, Object object) {
641 if (object == null) return runtime.getNil();
642 return RubyBignum.newBignum(runtime, (BigInteger)object);
646 private static final Map<Class,JavaConverter> JAVA_CONVERTERS =
647 new HashMap<Class,JavaConverter>();
649 static {
650 JAVA_CONVERTERS.put(Byte.class, JAVA_BYTE_CONVERTER);
651 JAVA_CONVERTERS.put(Byte.TYPE, JAVA_BYTE_CONVERTER);
652 JAVA_CONVERTERS.put(Short.class, JAVA_SHORT_CONVERTER);
653 JAVA_CONVERTERS.put(Short.TYPE, JAVA_SHORT_CONVERTER);
654 JAVA_CONVERTERS.put(Character.class, JAVA_CHAR_CONVERTER);
655 JAVA_CONVERTERS.put(Character.TYPE, JAVA_CHAR_CONVERTER);
656 JAVA_CONVERTERS.put(Integer.class, JAVA_INT_CONVERTER);
657 JAVA_CONVERTERS.put(Integer.TYPE, JAVA_INT_CONVERTER);
658 JAVA_CONVERTERS.put(Long.class, JAVA_LONG_CONVERTER);
659 JAVA_CONVERTERS.put(Long.TYPE, JAVA_LONG_CONVERTER);
660 JAVA_CONVERTERS.put(Float.class, JAVA_FLOAT_CONVERTER);
661 JAVA_CONVERTERS.put(Float.TYPE, JAVA_FLOAT_CONVERTER);
662 JAVA_CONVERTERS.put(Double.class, JAVA_DOUBLE_CONVERTER);
663 JAVA_CONVERTERS.put(Double.TYPE, JAVA_DOUBLE_CONVERTER);
664 JAVA_CONVERTERS.put(Boolean.class, JAVA_BOOLEAN_CONVERTER);
665 JAVA_CONVERTERS.put(Boolean.TYPE, JAVA_BOOLEAN_CONVERTER);
667 JAVA_CONVERTERS.put(String.class, JAVA_STRING_CONVERTER);
669 JAVA_CONVERTERS.put(ByteList.class, BYTELIST_CONVERTER);
671 JAVA_CONVERTERS.put(BigInteger.class, JAVA_BIGINTEGER_CONVERTER);
675 public static JavaConverter getJavaConverter(Class clazz) {
676 JavaConverter converter = JAVA_CONVERTERS.get(clazz);
678 if (converter == null) {
679 converter = JAVA_DEFAULT_CONVERTER;
682 return converter;
686 * Converts object to the corresponding Ruby type; however, for non-primitives,
687 * a JavaObject instance is returned. This must be subsequently wrapped by
688 * calling one of Java.wrap, Java.java_to_ruby, Java.new_instance_for, or
689 * Java.getInstance, depending on context.
691 * @param runtime
692 * @param object
693 * @return corresponding Ruby type, or a JavaObject instance
695 public static IRubyObject convertJavaToRuby(Ruby runtime, Object object) {
696 if (object == null) {
697 return runtime.getNil();
698 } else if (object instanceof IRubyObject) {
699 return (IRubyObject)object;
701 return convertJavaToRuby(runtime, object, object.getClass());
704 public static IRubyObject convertJavaToRuby(Ruby runtime, int i) {
705 return runtime.newFixnum(i);
708 public static IRubyObject convertJavaToRuby(Ruby runtime, long l) {
709 return runtime.newFixnum(l);
712 public static IRubyObject convertJavaToRuby(Ruby runtime, float f) {
713 return runtime.newFloat(f);
716 public static IRubyObject convertJavaToRuby(Ruby runtime, double d) {
717 return runtime.newFloat(d);
720 public static IRubyObject convertJavaToRuby(Ruby runtime, boolean b) {
721 return runtime.newBoolean(b);
724 public static IRubyObject convertJavaToRuby(Ruby runtime, Object object, Class javaClass) {
725 return getJavaConverter(javaClass).convert(runtime, object);
729 * Returns a usable RubyObject; for types that are not converted to Ruby native
730 * types, a Java proxy will be returned.
732 * @param runtime
733 * @param object
734 * @return corresponding Ruby type, or a functional Java proxy
736 public static IRubyObject convertJavaToUsableRubyObject(Ruby runtime, Object object) {
737 if (object == null) return runtime.getNil();
739 // if it's already IRubyObject, don't re-wrap (JRUBY-2480)
740 if (object instanceof IRubyObject) {
741 return (IRubyObject)object;
744 JavaConverter converter = JAVA_CONVERTERS.get(object.getClass());
745 if (converter == null || converter == JAVA_DEFAULT_CONVERTER) {
746 return Java.getInstance(runtime, object);
748 return converter.convert(runtime, object);
751 public static Class<?> primitiveToWrapper(Class<?> type) {
752 if (type.isPrimitive()) {
753 if (type == Integer.TYPE) {
754 return Integer.class;
755 } else if (type == Double.TYPE) {
756 return Double.class;
757 } else if (type == Boolean.TYPE) {
758 return Boolean.class;
759 } else if (type == Byte.TYPE) {
760 return Byte.class;
761 } else if (type == Character.TYPE) {
762 return Character.class;
763 } else if (type == Float.TYPE) {
764 return Float.class;
765 } else if (type == Long.TYPE) {
766 return Long.class;
767 } else if (type == Void.TYPE) {
768 return Void.class;
769 } else if (type == Short.TYPE) {
770 return Short.class;
773 return type;
776 public static Object convertArgument(Ruby runtime, Object argument, Class<?> parameterType) {
777 if (argument == null) {
778 if(parameterType.isPrimitive()) {
779 throw runtime.newTypeError("primitives do not accept null");
780 } else {
781 return null;
785 if (argument instanceof JavaObject) {
786 argument = ((JavaObject) argument).getValue();
787 if (argument == null) {
788 return null;
791 Class<?> type = primitiveToWrapper(parameterType);
792 if (type == Void.class) {
793 return null;
795 if (argument instanceof Number) {
796 final Number number = (Number) argument;
797 if (type == Long.class) {
798 return new Long(number.longValue());
799 } else if (type == Integer.class) {
800 return new Integer(number.intValue());
801 } else if (type == Byte.class) {
802 return new Byte(number.byteValue());
803 } else if (type == Character.class) {
804 return new Character((char) number.intValue());
805 } else if (type == Double.class) {
806 return new Double(number.doubleValue());
807 } else if (type == Float.class) {
808 return new Float(number.floatValue());
809 } else if (type == Short.class) {
810 return new Short(number.shortValue());
813 if (isDuckTypeConvertable(argument.getClass(), parameterType)) {
814 RubyObject rubyObject = (RubyObject) argument;
815 if (!rubyObject.respondsTo("java_object")) {
816 return convertProcToInterface(runtime.getCurrentContext(), rubyObject, parameterType);
819 return argument;
822 public static boolean isDuckTypeConvertable(Class providedArgumentType, Class parameterType) {
823 return parameterType.isInterface() && !parameterType.isAssignableFrom(providedArgumentType)
824 && RubyObject.class.isAssignableFrom(providedArgumentType);
827 public static Object convertProcToInterface(ThreadContext context, RubyObject rubyObject, Class target) {
828 Ruby runtime = context.getRuntime();
829 IRubyObject javaUtilities = runtime.getJavaSupport().getJavaUtilitiesModule();
830 IRubyObject javaInterfaceModule = Java.get_interface_module(javaUtilities, JavaClass.get(runtime, target));
831 if (!((RubyModule) javaInterfaceModule).isInstance(rubyObject)) {
832 rubyObject.extend(new IRubyObject[]{javaInterfaceModule});
835 if (rubyObject instanceof RubyProc) {
836 // Proc implementing an interface, pull in the catch-all code that lets the proc get invoked
837 // no matter what method is called on the interface
838 RubyClass singletonClass = rubyObject.getSingletonClass();
839 final RubyProc proc = (RubyProc) rubyObject;
841 singletonClass.addMethod("method_missing", new DynamicMethod(singletonClass, Visibility.PUBLIC, CallConfiguration.NO_FRAME_NO_SCOPE) {
843 @Override
844 public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
845 IRubyObject[] newArgs;
846 if (args.length == 1) {
847 newArgs = IRubyObject.NULL_ARRAY;
848 } else {
849 newArgs = new IRubyObject[args.length - 1];
850 System.arraycopy(args, 1, newArgs, 0, args.length - 1);
852 return proc.call(context, newArgs);
855 @Override
856 public DynamicMethod dup() {
857 return this;
861 JavaObject jo = (JavaObject) rubyObject.instance_eval(context, runtime.newString("send :__jcreate_meta!"), Block.NULL_BLOCK);
862 return jo.getValue();
865 public static Object convertArgumentToType(ThreadContext context, IRubyObject arg, Class target) {
866 if (arg instanceof JavaObject) {
867 return coerceJavaObjectToType(context, ((JavaObject)arg).getValue(), target);
868 } else if (arg.dataGetStruct() instanceof JavaObject) {
869 JavaObject innerWrapper = (JavaObject)arg.dataGetStruct();
871 // ensure the object is associated with the wrapper we found it in,
872 // so that if it comes back we don't re-wrap it
873 context.getRuntime().getJavaSupport().getObjectProxyCache().put(innerWrapper.getValue(), arg);
875 return innerWrapper.getValue();
876 } else {
877 switch (arg.getMetaClass().index) {
878 case ClassIndex.NIL:
879 return coerceNilToType((RubyNil)arg, target);
880 case ClassIndex.FIXNUM:
881 return coerceFixnumToType((RubyFixnum)arg, target);
882 case ClassIndex.BIGNUM:
883 return coerceBignumToType((RubyBignum)arg, target);
884 case ClassIndex.FLOAT:
885 return coerceFloatToType((RubyFloat)arg, target);
886 case ClassIndex.STRING:
887 return coerceStringToType((RubyString)arg, target);
888 case ClassIndex.TRUE:
889 return Boolean.TRUE;
890 case ClassIndex.FALSE:
891 return Boolean.FALSE;
892 case ClassIndex.TIME:
893 return ((RubyTime) arg).getJavaDate();
894 default:
895 return coerceOtherToType(context, arg, target);
900 public static Object coerceJavaObjectToType(ThreadContext context, Object javaObject, Class target) {
901 if (isDuckTypeConvertable(javaObject.getClass(), target)) {
902 RubyObject rubyObject = (RubyObject) javaObject;
903 if (!rubyObject.respondsTo("java_object")) {
904 return convertProcToInterface(context, rubyObject, target);
907 // can't be converted any more, return it
908 return javaObject;
909 } else {
910 return javaObject;
914 public static Object coerceNilToType(RubyNil nil, Class target) {
915 if(target.isPrimitive()) {
916 throw nil.getRuntime().newTypeError("primitives do not accept null");
917 } else {
918 return null;
922 public static Object coerceFixnumToType(RubyFixnum fixnum, Class target) {
923 if (target.isPrimitive()) {
924 if (target == Integer.TYPE) {
925 return Integer.valueOf((int)fixnum.getLongValue());
926 } else if (target == Double.TYPE) {
927 return Double.valueOf(fixnum.getLongValue());
928 } else if (target == Byte.TYPE) {
929 return Byte.valueOf((byte)fixnum.getLongValue());
930 } else if (target == Character.TYPE) {
931 return Character.valueOf((char)fixnum.getLongValue());
932 } else if (target == Float.TYPE) {
933 return Float.valueOf((float)fixnum.getLongValue());
934 } else if (target == Long.TYPE) {
935 return Long.valueOf(fixnum.getLongValue());
936 } else if (target == Short.TYPE) {
937 return Short.valueOf((short)fixnum.getLongValue());
940 return Long.valueOf(fixnum.getLongValue());
943 public static Object coerceBignumToType(RubyBignum bignum, Class target) {
944 if (target.isPrimitive()) {
945 if (target == Integer.TYPE) {
946 return Integer.valueOf((int)bignum.getLongValue());
947 } else if (target == Double.TYPE) {
948 return Double.valueOf(bignum.getLongValue());
949 } else if (target == Byte.TYPE) {
950 return Byte.valueOf((byte)bignum.getLongValue());
951 } else if (target == Character.TYPE) {
952 return Character.valueOf((char)bignum.getLongValue());
953 } else if (target == Float.TYPE) {
954 return Float.valueOf((float)bignum.getLongValue());
955 } else if (target == Long.TYPE) {
956 return Long.valueOf(bignum.getLongValue());
957 } else if (target == Short.TYPE) {
958 return Short.valueOf((short)bignum.getLongValue());
961 return bignum.getValue();
964 public static Object coerceFloatToType(RubyFloat flote, Class target) {
965 if (target.isPrimitive()) {
966 if (target == Integer.TYPE) {
967 return Integer.valueOf((int)flote.getLongValue());
968 } else if (target == Double.TYPE) {
969 return Double.valueOf(flote.getDoubleValue());
970 } else if (target == Byte.TYPE) {
971 return Byte.valueOf((byte)flote.getLongValue());
972 } else if (target == Character.TYPE) {
973 return Character.valueOf((char)flote.getLongValue());
974 } else if (target == Float.TYPE) {
975 return Float.valueOf((float)flote.getDoubleValue());
976 } else if (target == Long.TYPE) {
977 return Long.valueOf(flote.getLongValue());
978 } else if (target == Short.TYPE) {
979 return Short.valueOf((short)flote.getLongValue());
982 return Double.valueOf(flote.getDoubleValue());
985 public static Object coerceStringToType(RubyString string, Class target) {
986 try {
987 ByteList bytes = string.getByteList();
988 return new String(bytes.unsafeBytes(), bytes.begin(), bytes.length(), "UTF8");
989 } catch (UnsupportedEncodingException uee) {
990 return string.toString();
994 public static Object coerceOtherToType(ThreadContext context, IRubyObject arg, Class target) {
995 Ruby runtime = context.getRuntime();
997 if (isDuckTypeConvertable(arg.getClass(), target)) {
998 RubyObject rubyObject = (RubyObject) arg;
999 if (!rubyObject.respondsTo("java_object")) {
1000 return convertProcToInterface(context, rubyObject, target);
1002 } else if (arg.respondsTo("to_java_object")) {
1003 Object javaObject = arg.callMethod(context, "to_java_object");
1004 if (javaObject instanceof JavaObject) {
1005 runtime.getJavaSupport().getObjectProxyCache().put(((JavaObject) javaObject).getValue(), arg);
1006 javaObject = ((JavaObject)javaObject).getValue();
1008 return javaObject;
1011 // it's either as converted as we can make it via above logic or it's
1012 // not one of the types we convert, so just pass it out as-is without wrapping
1013 return arg;
1016 public static IRubyObject primitive_to_java(IRubyObject recv, IRubyObject object, Block unusedBlock) {
1017 if (object instanceof JavaObject) {
1018 return object;
1020 Ruby runtime = recv.getRuntime();
1021 Object javaObject;
1022 switch (object.getMetaClass().index) {
1023 case ClassIndex.NIL:
1024 javaObject = null;
1025 break;
1026 case ClassIndex.FIXNUM:
1027 javaObject = new Long(((RubyFixnum) object).getLongValue());
1028 break;
1029 case ClassIndex.BIGNUM:
1030 javaObject = ((RubyBignum) object).getValue();
1031 break;
1032 case ClassIndex.FLOAT:
1033 javaObject = new Double(((RubyFloat) object).getValue());
1034 break;
1035 case ClassIndex.STRING:
1036 try {
1037 ByteList bytes = ((RubyString) object).getByteList();
1038 javaObject = new String(bytes.unsafeBytes(), bytes.begin(), bytes.length(), "UTF8");
1039 } catch (UnsupportedEncodingException uee) {
1040 javaObject = object.toString();
1042 break;
1043 case ClassIndex.TRUE:
1044 javaObject = Boolean.TRUE;
1045 break;
1046 case ClassIndex.FALSE:
1047 javaObject = Boolean.FALSE;
1048 break;
1049 case ClassIndex.TIME:
1050 javaObject = ((RubyTime) object).getJavaDate();
1051 break;
1052 default:
1053 // it's not one of the types we convert, so just pass it out as-is without wrapping
1054 return object;
1057 // we've found a Java type to which we've coerced the Ruby value, wrap it
1058 return JavaObject.wrap(runtime, javaObject);
1062 * High-level object conversion utility function 'java_to_primitive' is the low-level version
1064 public static IRubyObject java_to_ruby(Ruby runtime, IRubyObject object) {
1065 if (object instanceof JavaObject) {
1066 return JavaUtil.convertJavaToUsableRubyObject(runtime, ((JavaObject) object).getValue());
1068 return object;
1071 // TODO: Formalize conversion mechanisms between Java and Ruby
1073 * High-level object conversion utility.
1075 public static IRubyObject ruby_to_java(final IRubyObject recv, IRubyObject object, Block unusedBlock) {
1076 if (object.respondsTo("to_java_object")) {
1077 IRubyObject result = (JavaObject)object.dataGetStruct();
1078 if (result == null) {
1079 result = object.callMethod(recv.getRuntime().getCurrentContext(), "to_java_object");
1081 if (result instanceof JavaObject) {
1082 recv.getRuntime().getJavaSupport().getObjectProxyCache().put(((JavaObject) result).getValue(), object);
1084 return result;
1087 return primitive_to_java(recv, object, unusedBlock);
1090 public static IRubyObject java_to_primitive(IRubyObject recv, IRubyObject object, Block unusedBlock) {
1091 if (object instanceof JavaObject) {
1092 return JavaUtil.convertJavaToRuby(recv.getRuntime(), ((JavaObject) object).getValue());
1095 return object;
1098 public static boolean isJavaObject(IRubyObject candidate) {
1099 return candidate.dataGetStruct() instanceof JavaObject;
1102 public static Object unwrapJavaObject(IRubyObject object) {
1103 return ((JavaObject)object.dataGetStruct()).getValue();
1106 private static final Pattern JAVA_PROPERTY_CHOPPER = Pattern.compile("(get|set|is)([A-Z0-9])(.*)");
1107 public static String getJavaPropertyName(String beanMethodName) {
1108 Matcher m = JAVA_PROPERTY_CHOPPER.matcher(beanMethodName);
1110 if (!m.find()) return null;
1111 String javaPropertyName = m.group(2).toLowerCase() + m.group(3);
1112 return javaPropertyName;
1115 private static final Pattern CAMEL_CASE_SPLITTER = Pattern.compile("([a-z][0-9]*)([A-Z])");
1116 public static String getRubyCasedName(String javaCasedName) {
1117 Matcher m = CAMEL_CASE_SPLITTER.matcher(javaCasedName);
1118 return m.replaceAll("$1_$2").toLowerCase();
1121 private static final Pattern RUBY_CASE_SPLITTER = Pattern.compile("([a-z][0-9]*)_([a-z])");
1122 public static String getJavaCasedName(String javaCasedName) {
1123 Matcher m = RUBY_CASE_SPLITTER.matcher(javaCasedName);
1124 StringBuffer newName = new StringBuffer();
1125 if (!m.find()) {
1126 return null;
1128 m.reset();
1130 while (m.find()) {
1131 m.appendReplacement(newName, m.group(1) + Character.toUpperCase(m.group(2).charAt(0)));
1134 m.appendTail(newName);
1136 return newName.toString();
1140 * Given a simple Java method name and the Java Method objects that represent
1141 * all its overloads, add to the given nameSet all possible Ruby names that would
1142 * be valid.
1144 * @param simpleName
1145 * @param nameSet
1146 * @param methods
1148 public static Set<String> getRubyNamesForJavaName(String javaName, List<Method> methods) {
1149 String javaPropertyName = JavaUtil.getJavaPropertyName(javaName);
1150 String rubyName = JavaUtil.getRubyCasedName(javaName);
1151 Set<String> nameSet = new LinkedHashSet<String>();
1152 nameSet.add(javaName);
1153 nameSet.add(rubyName);
1154 String rubyPropertyName = null;
1155 for (Method method: methods) {
1156 Class<?>[] argTypes = method.getParameterTypes();
1157 Class<?> resultType = method.getReturnType();
1158 int argCount = argTypes.length;
1160 // Add property name aliases
1161 if (javaPropertyName != null) {
1162 if (rubyName.startsWith("get_")) {
1163 rubyPropertyName = rubyName.substring(4);
1164 if (argCount == 0 || // getFoo => foo
1165 argCount == 1 && argTypes[0] == int.class) { // getFoo(int) => foo(int)
1167 nameSet.add(javaPropertyName);
1168 nameSet.add(rubyPropertyName);
1169 if (resultType == boolean.class) { // getFooBar() => fooBar?, foo_bar?(*)
1170 nameSet.add(javaPropertyName + '?');
1171 nameSet.add(rubyPropertyName + '?');
1174 } else if (rubyName.startsWith("set_")) {
1175 rubyPropertyName = rubyName.substring(4);
1176 if (argCount == 1 && resultType == void.class) { // setFoo(Foo) => foo=(Foo)
1177 nameSet.add(javaPropertyName + '=');
1178 nameSet.add(rubyPropertyName + '=');
1180 } else if (rubyName.startsWith("is_")) {
1181 rubyPropertyName = rubyName.substring(3);
1182 if (resultType == boolean.class) { // isFoo() => foo, isFoo(*) => foo(*)
1183 nameSet.add(javaPropertyName);
1184 nameSet.add(rubyPropertyName);
1185 nameSet.add(javaPropertyName + '?');
1186 nameSet.add(rubyPropertyName + '?');
1189 } else {
1190 // If not a property, but is boolean add ?-postfixed aliases.
1191 if (resultType == boolean.class) {
1192 // is_something?, contains_thing?
1193 nameSet.add(javaName + '?');
1194 nameSet.add(rubyName + '?');
1199 return nameSet;
1202 public static JavaObject unwrapJavaObject(Ruby runtime, IRubyObject convertee, String errorMessage) {
1203 IRubyObject obj = convertee;
1204 if(!(obj instanceof JavaObject)) {
1205 if (obj.dataGetStruct() != null && (obj.dataGetStruct() instanceof JavaObject)) {
1206 obj = (JavaObject)obj.dataGetStruct();
1207 } else {
1208 throw runtime.newTypeError(errorMessage);
1211 return (JavaObject)obj;