static Object coerceTypeImpl()

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;
    }