Skip to content

Commit ff88982

Browse files
committedFeb 27, 2018
Generify IRubyObject.toJava to make it more pleasant to use.
This change allow callers to skip the cast when calling toJava on a Ruby object. It was initially done to assist work on #4781 by allowing a simple "throw rubyException.toJava(Throwable.class). I tested binary compatibility in two ways: * A full recompile with all generification in place plus testing standard JRuby commands. This confirms that classes recompiled against the API but without other use of generics still function properly. * A partial recompile with only the generified classes rebuilt. This tests that classes not compiled against the API still function properly. Of course any external JRuby extensions (readline, openssl) will have been tested by running those standard commands (e.g. irb, gem install).
1 parent 6a0bb07 commit ff88982

19 files changed

+128
-141
lines changed
 

‎core/src/main/java/org/jruby/RubyArray.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -4969,7 +4969,7 @@ public Object[] toArray(final Object[] arg) {
49694969
}
49704970

49714971
@Override
4972-
public Object toJava(Class target) {
4972+
public <T> T toJava(Class<T> target) {
49734973
if (target.isArray()) {
49744974
Class type = target.getComponentType();
49754975
Object rawJavaArray = Array.newInstance(type, realLength);
@@ -4978,7 +4978,7 @@ public Object toJava(Class target) {
49784978
} catch (ArrayIndexOutOfBoundsException ex) {
49794979
throw concurrentModification(getRuntime(), ex);
49804980
}
4981-
return rawJavaArray;
4981+
return target.cast(rawJavaArray);
49824982
} else {
49834983
return super.toJava(target);
49844984
}

‎core/src/main/java/org/jruby/RubyBasicObject.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ public IRubyObject checkArrayType() {
856856
* @see IRubyObject#toJava
857857
*/
858858
@Override
859-
public Object toJava(Class target) {
859+
public <T> T toJava(Class<T> target) {
860860
return defaultToJava(target);
861861
}
862862

‎core/src/main/java/org/jruby/RubyBoolean.java

+26-11
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,19 @@ public static IRubyObject false_xor(IRubyObject f, IRubyObject oth) {
161161
public static RubyString false_to_s(IRubyObject f) {
162162
return RubyString.newStringShared(f.getRuntime(), FALSE_BYTES);
163163
}
164+
165+
/*
166+
Because Boolean objects can't cast to boolean via Class.cast, and you can't return
167+
a primitive from a generified method, this impl remains ungenerified.
168+
*/
169+
@Override
170+
public Object toJava(Class target) {
171+
if (target.isAssignableFrom(Boolean.class) | target.equals(boolean.class)) {
172+
return Boolean.FALSE;
173+
} else {
174+
return super.toJava(target);
175+
}
176+
}
164177
}
165178

166179
static final ByteList TRUE_BYTES = new ByteList(new byte[] { 't','r','u','e' }, USASCIIEncoding.INSTANCE);
@@ -192,6 +205,19 @@ public static IRubyObject true_xor(IRubyObject t, IRubyObject oth) {
192205
public static RubyString true_to_s(IRubyObject t) {
193206
return RubyString.newStringShared(t.getRuntime(), TRUE_BYTES);
194207
}
208+
209+
/*
210+
Because Boolean objects can't cast to boolean via Class.cast, and you can't return
211+
a primitive from a generified method, this impl remains ungenerified.
212+
*/
213+
@Override
214+
public Object toJava(Class target) {
215+
if (target.isAssignableFrom(Boolean.class) | target.equals(boolean.class)) {
216+
return Boolean.TRUE;
217+
} else {
218+
return super.toJava(target);
219+
}
220+
}
195221
}
196222

197223
@JRubyMethod(name = "hash")
@@ -221,16 +247,5 @@ public IRubyObject taint(ThreadContext context) {
221247
public void marshalTo(MarshalStream output) throws java.io.IOException {
222248
output.write(isTrue() ? 'T' : 'F');
223249
}
224-
225-
@Override
226-
public Object toJava(Class target) {
227-
if (target.isAssignableFrom(Boolean.class) || target.equals(boolean.class)) {
228-
if (isFalse()) return Boolean.FALSE;
229-
230-
return Boolean.TRUE;
231-
} else {
232-
return super.toJava(target);
233-
}
234-
}
235250
}
236251

‎core/src/main/java/org/jruby/RubyClass.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,7 @@ public synchronized void addClassAnnotation(Class annotation, Map fields) {
18861886
}
18871887

18881888
@Override
1889-
public Object toJava(final Class target) {
1889+
public <T> T toJava(Class<T> target) {
18901890
if (target == Class.class) {
18911891
if (reifiedClass == null) reifyWithAncestors(); // possibly auto-reify
18921892
// Class requested; try java_class or else return nearest reified class
@@ -1895,13 +1895,13 @@ public Object toJava(final Class target) {
18951895
if ( ! javaClass.isNil() ) return javaClass.toJava(target);
18961896

18971897
Class reifiedClass = nearestReifiedClass(this);
1898-
if ( reifiedClass != null ) return reifiedClass;
1898+
if ( reifiedClass != null ) return target.cast(reifiedClass);
18991899
// should never fall through, since RubyObject has a reified class
19001900
}
19011901

19021902
if (target.isAssignableFrom(RubyClass.class)) {
19031903
// they're asking for something RubyClass extends, give them that
1904-
return this;
1904+
return target.cast(this);
19051905
}
19061906

19071907
return defaultToJava(target);

‎core/src/main/java/org/jruby/RubyFile.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -2028,10 +2028,10 @@ private static RubyString checkHome(ThreadContext context) {
20282028
}
20292029

20302030
@Override
2031-
public Object toJava(Class target) {
2032-
if (target == java.io.File.class) {
2031+
public <T> T toJava(Class<T> target) {
2032+
if (target == File.class) {
20332033
final String path = getPath();
2034-
return path == null ? null : new java.io.File(path);
2034+
return path == null ? null : target.cast(new File(path));
20352035
}
20362036
return super.toJava(target);
20372037
}

‎core/src/main/java/org/jruby/RubyIO.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -4752,14 +4752,14 @@ public boolean getBOM() {
47524752
}
47534753

47544754
@Override
4755-
public Object toJava(Class target) {
4755+
public <T> T toJava(Class<T> target) {
47564756
if (target == java.io.InputStream.class) {
47574757
getOpenFile().checkReadable(getRuntime().getCurrentContext());
4758-
return getInStream();
4758+
return target.cast(getInStream());
47594759
}
47604760
if (target == java.io.OutputStream.class) {
47614761
getOpenFile().checkWritable(getRuntime().getCurrentContext());
4762-
return getOutStream();
4762+
return target.cast(getOutStream());
47634763
}
47644764
return super.toJava(target);
47654765
}

‎core/src/main/java/org/jruby/RubyModule.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4718,7 +4718,7 @@ public void setCacheProxy(boolean cacheProxy) {
47184718
}
47194719

47204720
@Override
4721-
public Object toJava(final Class target) {
4721+
public <T> T toJava(Class<T> target) {
47224722
if (target == Class.class) { // try java_class for proxy modules
47234723
final ThreadContext context = getRuntime().getCurrentContext();
47244724
IRubyObject javaClass = JavaClass.java_class(context, this);

‎core/src/main/java/org/jruby/RubyNil.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -249,24 +249,24 @@ public static IRubyObject rationalize(ThreadContext context, IRubyObject recv, I
249249
}
250250

251251
@Override
252-
public Object toJava(Class target) {
252+
public <T> T toJava(Class<T> target) {
253253
if (target.isPrimitive()) {
254254
if (target == Boolean.TYPE) {
255-
return Boolean.FALSE;
255+
return target.cast(false);
256256
} else if (target == Byte.TYPE) {
257-
return (byte)0;
257+
return target.cast((byte)0);
258258
} else if (target == Short.TYPE) {
259-
return (short)0;
259+
return target.cast((short)0);
260260
} else if (target == Character.TYPE) {
261-
return (char)0;
261+
return target.cast((char)0);
262262
} else if (target == Integer.TYPE) {
263-
return 0;
263+
return target.cast(0);
264264
} else if (target == Long.TYPE) {
265-
return (long)0;
265+
return target.cast(0L);
266266
} else if (target == Float.TYPE) {
267-
return (float)0;
267+
return target.cast(0F);
268268
} else if (target == Double.TYPE) {
269-
return (double)0;
269+
return target.cast(0.0);
270270
}
271271
}
272272
return null;

‎core/src/main/java/org/jruby/RubyNumeric.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,7 @@ public IRubyObject conjugate(ThreadContext context) {
13371337
}
13381338

13391339
@Override
1340-
public Object toJava(Class target) {
1340+
public <T> T toJava(Class<T> target) {
13411341
return JavaUtil.getNumericConverter(target).coerce(this, target);
13421342
}
13431343

‎core/src/main/java/org/jruby/RubyString.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -5624,18 +5624,18 @@ public static ByteList encodeBytelist(CharSequence value, Encoding encoding) {
56245624
}
56255625

56265626
@Override
5627-
public Object toJava(Class target) {
5627+
public <T> T toJava(Class<T> target) {
56285628
if (target.isAssignableFrom(String.class)) {
5629-
return decodeString();
5629+
return target.cast(decodeString());
56305630
}
56315631
if (target.isAssignableFrom(ByteList.class)) {
5632-
return value;
5632+
return target.cast(value);
56335633
}
56345634
if (target == Character.class || target == Character.TYPE) {
56355635
if ( strLength() != 1 ) {
56365636
throw getRuntime().newArgumentError("could not coerce string of length " + strLength() + " (!= 1) into a char");
56375637
}
5638-
return decodeString().charAt(0);
5638+
return target.cast(decodeString().charAt(0));
56395639
}
56405640
return super.toJava(target);
56415641
}

‎core/src/main/java/org/jruby/RubySymbol.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,8 @@ public static RubySymbol unmarshalFrom(UnmarshalStream input) throws java.io.IOE
646646
}
647647

648648
@Override
649-
public Object toJava(Class target) {
650-
if (target == String.class || target == CharSequence.class) return symbol;
649+
public <T> T toJava(Class<T> target) {
650+
if (target == String.class || target == CharSequence.class) return target.cast(symbol);
651651

652652
return super.toJava(target);
653653
}

‎core/src/main/java/org/jruby/RubyTime.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -1285,27 +1285,27 @@ public static RubyTime load(ThreadContext context, IRubyObject recv, IRubyObject
12851285
}
12861286

12871287
@Override
1288-
public Object toJava(Class target) {
1288+
public <T> T toJava(Class<T> target) {
12891289
if (target == Date.class) {
1290-
return getJavaDate();
1290+
return target.cast(getJavaDate());
12911291
}
12921292
if (target == Calendar.class || target == GregorianCalendar.class) {
1293-
return dt.toGregorianCalendar();
1293+
return target.cast(dt.toGregorianCalendar());
12941294
}
12951295
if (target == DateTime.class) {
1296-
return this.dt;
1296+
return target.cast(this.dt);
12971297
}
12981298
if (target == java.sql.Date.class) {
1299-
return new java.sql.Date(dt.getMillis());
1299+
return target.cast(new java.sql.Date(dt.getMillis()));
13001300
}
13011301
if (target == java.sql.Time.class) {
1302-
return new java.sql.Time(dt.getMillis());
1302+
return target.cast(new java.sql.Time(dt.getMillis()));
13031303
}
13041304
if (target == java.sql.Timestamp.class) {
1305-
return new java.sql.Timestamp(dt.getMillis());
1305+
return target.cast(new java.sql.Timestamp(dt.getMillis()));
13061306
}
13071307
if (target.isAssignableFrom(Date.class)) {
1308-
return getJavaDate();
1308+
return target.cast(getJavaDate());
13091309
}
13101310
return super.toJava(target);
13111311
}

‎core/src/main/java/org/jruby/java/proxies/ConcreteJavaProxy.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public IRubyObject id() {
210210

211211
@Override
212212
@SuppressWarnings("unchecked")
213-
public Object toJava(final Class type) {
213+
public <T> T toJava(Class<T> type) {
214214
final Object object = getObject();
215215
final Class clazz = object.getClass();
216216

@@ -222,16 +222,16 @@ public Object toJava(final Class type) {
222222
object instanceof Boolean && type == Boolean.TYPE ) {
223223
// FIXME in more permissive call paths, like invokedynamic, this can allow
224224
// precision-loading downcasts to happen silently
225-
return object;
225+
return (T) object;
226226
}
227227
}
228228
else if ( type.isAssignableFrom(clazz) ) {
229229
if ( Java.OBJECT_PROXY_CACHE || metaClass.getCacheProxy() ) {
230230
getRuntime().getJavaSupport().getObjectProxyCache().put(object, this);
231231
}
232-
return object;
232+
return type.cast(object);
233233
}
234-
else if ( type.isAssignableFrom(getClass()) ) return this; // e.g. IRubyObject.class
234+
else if ( type.isAssignableFrom(getClass()) ) return type.cast(this); // e.g. IRubyObject.class
235235

236236
throw getRuntime().newTypeError("failed to coerce " + clazz.getName() + " to " + type.getName());
237237
}

‎core/src/main/java/org/jruby/java/proxies/JavaProxy.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,12 @@ private RubyMethod getRubyMethod(ThreadContext context, String name, Class... ar
462462

463463
@Override
464464
@SuppressWarnings("unchecked")
465-
public Object toJava(final Class type) {
465+
public <T> T toJava(Class<T> type) {
466466
final Object object = getObject();
467467
final Class<?> clazz = object.getClass();
468468

469-
if ( type.isAssignableFrom(clazz) ) return object;
470-
if ( type.isAssignableFrom(getClass()) ) return this; // e.g. IRubyObject.class
469+
if ( type.isAssignableFrom(clazz) ) return type.cast(object);
470+
if ( type.isAssignableFrom(getClass()) ) return type.cast(this); // e.g. IRubyObject.class
471471

472472
throw getRuntime().newTypeError("failed to coerce " + clazz.getName() + " to " + type.getName());
473473
}

‎core/src/main/java/org/jruby/javasupport/JavaAccessibleObject.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,10 @@ public String toString() {
169169
}
170170

171171
@Override
172-
public Object toJava(Class target) {
173-
if ( AccessibleObject.class.isAssignableFrom(target) ) {
174-
return accessibleObject();
172+
public <T> T toJava(Class<T> target) {
173+
AccessibleObject accessibleObject = accessibleObject();
174+
if (target.isAssignableFrom(accessibleObject.getClass())) {
175+
return target.cast(accessibleObject);
175176
}
176177
return super.toJava(target);
177178
}

‎core/src/main/java/org/jruby/javasupport/JavaObject.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,12 @@ public IRubyObject marshal_load(ThreadContext context, IRubyObject str) {
301301

302302
@Override
303303
@SuppressWarnings("unchecked")
304-
public Object toJava(final Class target) {
304+
public <T> T toJava(Class<T> target) {
305305
final Object value = getValue();
306306
if ( value == null ) return null;
307307

308308
if ( target.isAssignableFrom( value.getClass() ) ) {
309-
return value;
309+
return target.cast(value);
310310
}
311311
return super.toJava(target);
312312
}

‎core/src/main/java/org/jruby/javasupport/JavaPackage.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,9 @@ public IRubyObject sealed_p(ThreadContext context) {
295295

296296
@Override
297297
@SuppressWarnings("unchecked")
298-
public Object toJava(final Class target) {
298+
public <T> T toJava(Class<T> target) {
299299
if ( target.isAssignableFrom( Package.class ) ) {
300-
return Package.getPackage(packageName);
300+
return target.cast(Package.getPackage(packageName));
301301
}
302302
return super.toJava(target);
303303
}

‎core/src/main/java/org/jruby/javasupport/JavaUtil.java

+49-78
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public static <T> T convertProcToInterface(ThreadContext context, RubyBasicObjec
264264
return (T) javaObject.getValue();
265265
}
266266

267-
public static NumericConverter getNumericConverter(Class target) {
267+
public static <T> NumericConverter<T> getNumericConverter(Class<T> target) {
268268
final NumericConverter converter = NUMERIC_CONVERTERS.get(target);
269269
return converter == null ? NUMERIC_TO_OTHER : converter;
270270
}
@@ -587,8 +587,8 @@ public static abstract class JavaConverter {
587587
public String toString() {return type.getName() + " converter";}
588588
}
589589

590-
public interface NumericConverter {
591-
public Object coerce(RubyNumeric numeric, Class target);
590+
public interface NumericConverter<T> {
591+
T coerce(RubyNumeric numeric, Class<T> target);
592592
}
593593

594594
private static IRubyObject trySimpleConversions(Ruby runtime, Object object) {
@@ -910,90 +910,61 @@ public void set(Ruby runtime, Object array, int i, IRubyObject value) {
910910
JAVA_CONVERTERS.put(BigInteger.class, JAVA_BIGINTEGER_CONVERTER);
911911
}
912912

913-
private static final NumericConverter NUMERIC_TO_BYTE = new NumericConverter() {
914-
public Object coerce(RubyNumeric numeric, Class target) {
915-
final long value = numeric.getLongValue();
916-
if ( isLongByteable(value) ) return (byte) value;
917-
throw numeric.getRuntime().newRangeError("too big for byte: " + numeric);
918-
}
919-
};
920-
private static final NumericConverter NUMERIC_TO_SHORT = new NumericConverter() {
921-
public Object coerce(RubyNumeric numeric, Class target) {
922-
final long value = numeric.getLongValue();
923-
if ( isLongShortable(value) ) return (short) value;
924-
throw numeric.getRuntime().newRangeError("too big for short: " + numeric);
925-
}
926-
};
927-
private static final NumericConverter NUMERIC_TO_CHARACTER = new NumericConverter() {
928-
public Object coerce(RubyNumeric numeric, Class target) {
929-
final long value = numeric.getLongValue();
930-
if ( isLongCharable(value) ) return (char) value;
931-
throw numeric.getRuntime().newRangeError("too big for char: " + numeric);
932-
}
913+
private static final NumericConverter<Byte> NUMERIC_TO_BYTE = (numeric, target) -> {
914+
final long value = numeric.getLongValue();
915+
if ( isLongByteable(value) ) return (byte) value;
916+
throw numeric.getRuntime().newRangeError("too big for byte: " + numeric);
933917
};
934-
private static final NumericConverter NUMERIC_TO_INTEGER = new NumericConverter() {
935-
public Object coerce(RubyNumeric numeric, Class target) {
936-
final long value = numeric.getLongValue();
937-
if ( isLongIntable(value) ) return (int) value;
938-
throw numeric.getRuntime().newRangeError("too big for int: " + numeric);
939-
}
918+
private static final NumericConverter<Short> NUMERIC_TO_SHORT = (numeric, target) -> {
919+
final long value = numeric.getLongValue();
920+
if ( isLongShortable(value) ) return (short) value;
921+
throw numeric.getRuntime().newRangeError("too big for short: " + numeric);
940922
};
941-
private static final NumericConverter NUMERIC_TO_LONG = new NumericConverter() {
942-
public Object coerce(RubyNumeric numeric, Class target) {
943-
return numeric.getLongValue();
944-
}
923+
private static final NumericConverter<Character> NUMERIC_TO_CHARACTER = (numeric, target) -> {
924+
final long value = numeric.getLongValue();
925+
if ( isLongCharable(value) ) return (char) value;
926+
throw numeric.getRuntime().newRangeError("too big for char: " + numeric);
945927
};
946-
private static final NumericConverter NUMERIC_TO_FLOAT = new NumericConverter() {
947-
public Object coerce(RubyNumeric numeric, Class target) {
948-
final double value = numeric.getDoubleValue();
949-
// many cases are ok to convert to float; if not one of these, error
950-
if ( isDoubleFloatable(value) ) return (float) value;
951-
throw numeric.getRuntime().newTypeError("too big for float: " + numeric);
952-
}
928+
private static final NumericConverter<Integer> NUMERIC_TO_INTEGER = (numeric, target) -> {
929+
final long value = numeric.getLongValue();
930+
if ( isLongIntable(value) ) return (int) value;
931+
throw numeric.getRuntime().newRangeError("too big for int: " + numeric);
953932
};
954-
private static final NumericConverter NUMERIC_TO_DOUBLE = new NumericConverter() {
955-
public Object coerce(RubyNumeric numeric, Class target) {
956-
return numeric.getDoubleValue();
957-
}
933+
private static final NumericConverter<Long> NUMERIC_TO_LONG = (numeric, target) -> numeric.getLongValue();
934+
private static final NumericConverter<Float> NUMERIC_TO_FLOAT = (numeric, target) -> {
935+
final double value = numeric.getDoubleValue();
936+
// many cases are ok to convert to float; if not one of these, error
937+
if ( isDoubleFloatable(value) ) return (float) value;
938+
throw numeric.getRuntime().newTypeError("too big for float: " + numeric);
958939
};
959-
private static final NumericConverter NUMERIC_TO_BIGINTEGER = new NumericConverter() {
960-
public Object coerce(RubyNumeric numeric, Class target) {
961-
return numeric.getBigIntegerValue();
962-
}
963-
};
964-
private static final NumericConverter NUMERIC_TO_OBJECT = new NumericConverter() {
965-
public Object coerce(RubyNumeric numeric, Class target) {
966-
// for Object, default to natural wrapper type
967-
if (numeric instanceof RubyFixnum) {
968-
long value = numeric.getLongValue();
969-
return Long.valueOf(value);
970-
} else if (numeric instanceof RubyFloat) {
971-
double value = numeric.getDoubleValue();
972-
return Double.valueOf(value);
973-
} else if (numeric instanceof RubyBignum) {
974-
return ((RubyBignum)numeric).getValue();
975-
} else if (numeric instanceof RubyBigDecimal) {
976-
return ((RubyBigDecimal)numeric).getValue();
977-
} else {
978-
return NUMERIC_TO_OTHER.coerce(numeric, target);
979-
}
980-
}
981-
};
982-
private static final NumericConverter NUMERIC_TO_OTHER = new NumericConverter() {
983-
public Object coerce(RubyNumeric numeric, Class target) {
984-
if (target.isAssignableFrom(numeric.getClass())) {
985-
// just return as-is, since we can't do any coercion
986-
return numeric;
987-
}
988-
// otherwise, error; no conversion available
989-
throw numeric.getRuntime().newTypeError("could not coerce " + numeric.getMetaClass() + " to " + target);
940+
private static final NumericConverter<Double> NUMERIC_TO_DOUBLE = (numeric, target) -> numeric.getDoubleValue();
941+
private static final NumericConverter<BigInteger> NUMERIC_TO_BIGINTEGER = (numeric, target) -> numeric.getBigIntegerValue();
942+
943+
private static final NumericConverter NUMERIC_TO_OTHER = (numeric, target) -> {
944+
if (target.isAssignableFrom(numeric.getClass())) {
945+
// just return as-is, since we can't do any coercion
946+
return numeric;
990947
}
948+
// otherwise, error; no conversion available
949+
throw numeric.getRuntime().newTypeError("could not coerce " + numeric.getMetaClass() + " to " + target);
991950
};
992-
private static final NumericConverter NUMERIC_TO_VOID = new NumericConverter() {
993-
public Object coerce(RubyNumeric numeric, Class target) {
994-
return null;
951+
private static final NumericConverter<Object> NUMERIC_TO_OBJECT = (numeric, target) -> {
952+
// for Object, default to natural wrapper type
953+
if (numeric instanceof RubyFixnum) {
954+
long value = numeric.getLongValue();
955+
return Long.valueOf(value);
956+
} else if (numeric instanceof RubyFloat) {
957+
double value = numeric.getDoubleValue();
958+
return Double.valueOf(value);
959+
} else if (numeric instanceof RubyBignum) {
960+
return ((RubyBignum)numeric).getValue();
961+
} else if (numeric instanceof RubyBigDecimal) {
962+
return ((RubyBigDecimal)numeric).getValue();
963+
} else {
964+
return NUMERIC_TO_OTHER.coerce(numeric, target);
995965
}
996966
};
967+
private static final NumericConverter NUMERIC_TO_VOID = (numeric, target) -> null;
997968
private static boolean isDoubleFloatable(double value) {
998969
return true;
999970
}

‎core/src/main/java/org/jruby/runtime/builtin/IRubyObject.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public interface IRubyObject {
275275
*
276276
* @param type The target type to which the object should be converted.
277277
*/
278-
Object toJava(Class type);
278+
<T> T toJava(Class<T> type);
279279

280280
/**
281281
* RubyMethod dup.

0 commit comments

Comments
 (0)
Please sign in to comment.