in rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java [486:646]
static Object coerceTypeImpl(Class<?> type, Object value) {
if (value != null && value.getClass() == type) {
return value;
}
int jsTypeCode = getJSTypeCode(value);
switch (jsTypeCode) {
case JSTYPE_NULL:
// raise error if type.isPrimitive()
if (type.isPrimitive()) {
reportConversionError(value, type);
}
return null;
case JSTYPE_UNDEFINED:
if (type == ScriptRuntime.StringClass || type == ScriptRuntime.ObjectClass) {
return "undefined";
}
reportConversionError("undefined", type);
break;
case JSTYPE_BOOLEAN:
// Under LC3, only JS Booleans can be coerced into a Boolean value
if (type == Boolean.TYPE
|| type == ScriptRuntime.BooleanClass
|| type == ScriptRuntime.ObjectClass) {
return value;
} else if (type == ScriptRuntime.StringClass) {
return value.toString();
} else {
reportConversionError(value, type);
}
break;
case JSTYPE_NUMBER:
case JSTYPE_BIGINT:
if (type == ScriptRuntime.StringClass) {
return ScriptRuntime.toString(value);
} else if (type == ScriptRuntime.ObjectClass) {
Context context = Context.getCurrentContext();
if ((context != null)
&& context.hasFeature(Context.FEATURE_INTEGER_WITHOUT_DECIMAL_PLACE)) {
// to process numbers like 2.0 as 2 without decimal place
long roundedValue = Math.round(toDouble(value));
if (roundedValue == toDouble(value)) {
return coerceToNumber(Long.TYPE, value);
}
}
return coerceToNumber(
jsTypeCode == JSTYPE_BIGINT ? BigInteger.class : Double.TYPE, value);
} else if ((type.isPrimitive() && type != Boolean.TYPE)
|| ScriptRuntime.NumberClass.isAssignableFrom(type)
|| ScriptRuntime.CharacterClass.isAssignableFrom(type)) {
return coerceToNumber(type, value);
} else {
reportConversionError(value, type);
}
break;
case JSTYPE_STRING:
if (type == ScriptRuntime.StringClass || type.isInstance(value)) {
return value.toString();
} else if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) {
// Special case for converting a single char string to a
// character
// Placed here because it applies *only* to JS strings,
// not other JS objects converted to strings
if (((CharSequence) value).length() == 1) {
return Character.valueOf(((CharSequence) value).charAt(0));
}
return coerceToNumber(type, value);
} else if ((type.isPrimitive() && type != Boolean.TYPE)
|| ScriptRuntime.NumberClass.isAssignableFrom(type)) {
return coerceToNumber(type, value);
} else {
reportConversionError(value, type);
}
break;
case JSTYPE_JAVA_CLASS:
if (value instanceof Wrapper) {
value = ((Wrapper) value).unwrap();
}
if (type == ScriptRuntime.ClassClass || type == ScriptRuntime.ObjectClass) {
return value;
} else if (type == ScriptRuntime.StringClass) {
return value.toString();
} else {
reportConversionError(value, type);
}
break;
case JSTYPE_JAVA_OBJECT:
case JSTYPE_JAVA_ARRAY:
if (value instanceof Wrapper) {
value = ((Wrapper) value).unwrap();
}
if (type.isPrimitive()) {
if (type == Boolean.TYPE) {
reportConversionError(value, type);
}
return coerceToNumber(type, value);
}
if (type == ScriptRuntime.StringClass) {
return value.toString();
}
if (type.isInstance(value)) {
return value;
}
reportConversionError(value, type);
break;
case JSTYPE_OBJECT:
if (type == ScriptRuntime.StringClass) {
return ScriptRuntime.toString(value);
} else if (type.isPrimitive()) {
if (type == Boolean.TYPE) {
reportConversionError(value, type);
}
return coerceToNumber(type, value);
} else if (type.isInstance(value)) {
return value;
} else if (type == ScriptRuntime.DateClass && value instanceof NativeDate) {
double time = ((NativeDate) value).getJSTimeValue();
// XXX: This will replace NaN by 0
return new Date((long) time);
} else if (type.isArray() && value instanceof NativeArray) {
// Make a new java array, and coerce the JS array components
// to the target (component) type.
NativeArray array = (NativeArray) value;
long length = array.getLength();
Class<?> arrayType = type.getComponentType();
Object Result = Array.newInstance(arrayType, (int) length);
for (int i = 0; i < length; ++i) {
try {
Array.set(Result, i, coerceTypeImpl(arrayType, array.get(i, array)));
} catch (EvaluatorException ee) {
reportConversionError(value, type);
}
}
return Result;
} else if (value instanceof Wrapper) {
value = ((Wrapper) value).unwrap();
if (type.isInstance(value)) return value;
reportConversionError(value, type);
} else if (type.isInterface()
&& (value instanceof NativeObject
|| (value instanceof Callable
&& value instanceof ScriptableObject))) {
// Try to use function/object as implementation of Java interface.
return createInterfaceAdapter(type, (ScriptableObject) value);
} else {
reportConversionError(value, type);
}
break;
}
return value;
}