Search in sources :

Example 1 with TemplateDateModel

use of freemarker.template.TemplateDateModel in project freemarker by apache.

the class EvalUtil method coerceModelToStringOrUnsupportedMarkup.

/**
 * Like {@link #coerceModelToStringOrMarkup(TemplateModel, Expression, String, Environment)}, but gives error
 * if the result is markup. This is what you normally use where markup results can't be used.
 *
 * @param seqTip
 *            Tip to display if the value type is not coercable, but it's sequence or collection.
 *
 * @return Never {@code null}
 */
static String coerceModelToStringOrUnsupportedMarkup(TemplateModel tm, Expression exp, String seqTip, Environment env) throws TemplateException {
    if (tm instanceof TemplateNumberModel) {
        TemplateNumberModel tnm = (TemplateNumberModel) tm;
        TemplateNumberFormat format = env.getTemplateNumberFormat(exp, false);
        try {
            return ensureFormatResultString(format.format(tnm), exp, env);
        } catch (TemplateValueFormatException e) {
            throw _MessageUtil.newCantFormatNumberException(format, exp, e, false);
        }
    } else if (tm instanceof TemplateDateModel) {
        TemplateDateModel tdm = (TemplateDateModel) tm;
        TemplateDateFormat format = env.getTemplateDateFormat(tdm, exp, false);
        try {
            return ensureFormatResultString(format.format(tdm), exp, env);
        } catch (TemplateValueFormatException e) {
            throw _MessageUtil.newCantFormatDateException(format, exp, e, false);
        }
    } else {
        return coerceModelToTextualCommon(tm, exp, seqTip, false, false, env);
    }
}
Also used : TemplateNumberModel(freemarker.template.TemplateNumberModel) TemplateDateModel(freemarker.template.TemplateDateModel)

Example 2 with TemplateDateModel

use of freemarker.template.TemplateDateModel in project freemarker by apache.

the class EvalUtil method coerceModelToStringOrMarkup.

/**
 * @return {@code null} if the {@code returnNullOnNonCoercableType} parameter is {@code true}, and the coercion is
 *         not possible, because of the type is not right for it.
 *
 * @see #coerceModelToStringOrMarkup(TemplateModel, Expression, String, Environment)
 */
static Object coerceModelToStringOrMarkup(TemplateModel tm, Expression exp, boolean returnNullOnNonCoercableType, String seqTip, Environment env) throws TemplateException {
    if (tm instanceof TemplateNumberModel) {
        TemplateNumberModel tnm = (TemplateNumberModel) tm;
        TemplateNumberFormat format = env.getTemplateNumberFormat(exp, false);
        try {
            return assertFormatResultNotNull(format.format(tnm));
        } catch (TemplateValueFormatException e) {
            throw _MessageUtil.newCantFormatNumberException(format, exp, e, false);
        }
    } else if (tm instanceof TemplateDateModel) {
        TemplateDateModel tdm = (TemplateDateModel) tm;
        TemplateDateFormat format = env.getTemplateDateFormat(tdm, exp, false);
        try {
            return assertFormatResultNotNull(format.format(tdm));
        } catch (TemplateValueFormatException e) {
            throw _MessageUtil.newCantFormatDateException(format, exp, e, false);
        }
    } else if (tm instanceof TemplateMarkupOutputModel) {
        return tm;
    } else {
        return coerceModelToTextualCommon(tm, exp, seqTip, true, returnNullOnNonCoercableType, env);
    }
}
Also used : TemplateNumberModel(freemarker.template.TemplateNumberModel) TemplateDateModel(freemarker.template.TemplateDateModel)

Example 3 with TemplateDateModel

use of freemarker.template.TemplateDateModel in project freemarker by apache.

the class BeansWrapper method tryUnwrapTo.

/**
 * See {@link #tryUnwrapTo(TemplateModel, Class, int)}.
 */
private Object tryUnwrapTo(final TemplateModel model, Class<?> targetClass, final int typeFlags, final Map<Object, Object> recursionStops) throws TemplateModelException {
    if (model == null || model == nullModel) {
        return null;
    }
    final boolean is2321Bugfixed = is2321Bugfixed();
    if (is2321Bugfixed && targetClass.isPrimitive()) {
        targetClass = ClassUtil.primitiveClassToBoxingClass(targetClass);
    }
    // passed as an argument to TemplateMethodModelEx etc.
    if (model instanceof AdapterTemplateModel) {
        Object wrapped = ((AdapterTemplateModel) model).getAdaptedObject(targetClass);
        if (targetClass == Object.class || targetClass.isInstance(wrapped)) {
            return wrapped;
        }
        // Attempt numeric conversion:
        if (targetClass != Object.class && (wrapped instanceof Number && ClassUtil.isNumerical(targetClass))) {
            Number number = forceUnwrappedNumberToType((Number) wrapped, targetClass, is2321Bugfixed);
            if (number != null)
                return number;
        }
    }
    if (model instanceof WrapperTemplateModel) {
        Object wrapped = ((WrapperTemplateModel) model).getWrappedObject();
        if (targetClass == Object.class || targetClass.isInstance(wrapped)) {
            return wrapped;
        }
        // Attempt numeric conversion:
        if (targetClass != Object.class && (wrapped instanceof Number && ClassUtil.isNumerical(targetClass))) {
            Number number = forceUnwrappedNumberToType((Number) wrapped, targetClass, is2321Bugfixed);
            if (number != null) {
                return number;
            }
        }
    }
    // know what is expected as the return type.
    if (targetClass != Object.class) {
        // [2.4][IcI]: Should also check for CharSequence at the end
        if (String.class == targetClass) {
            if (model instanceof TemplateScalarModel) {
                return ((TemplateScalarModel) model).getAsString();
            }
            // String is final, so no other conversion will work
            return ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS;
        }
        // Primitive numeric types & Number.class and its subclasses
        if (ClassUtil.isNumerical(targetClass)) {
            if (model instanceof TemplateNumberModel) {
                Number number = forceUnwrappedNumberToType(((TemplateNumberModel) model).getAsNumber(), targetClass, is2321Bugfixed);
                if (number != null) {
                    return number;
                }
            }
        }
        if (boolean.class == targetClass || Boolean.class == targetClass) {
            if (model instanceof TemplateBooleanModel) {
                return Boolean.valueOf(((TemplateBooleanModel) model).getAsBoolean());
            }
            // Boolean is final, no other conversion will work
            return ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS;
        }
        if (Map.class == targetClass) {
            if (model instanceof TemplateHashModel) {
                return new HashAdapter((TemplateHashModel) model, this);
            }
        }
        if (List.class == targetClass) {
            if (model instanceof TemplateSequenceModel) {
                return new SequenceAdapter((TemplateSequenceModel) model, this);
            }
        }
        if (Set.class == targetClass) {
            if (model instanceof TemplateCollectionModel) {
                return new SetAdapter((TemplateCollectionModel) model, this);
            }
        }
        if (Collection.class == targetClass || Iterable.class == targetClass) {
            if (model instanceof TemplateCollectionModel) {
                return new CollectionAdapter((TemplateCollectionModel) model, this);
            }
            if (model instanceof TemplateSequenceModel) {
                return new SequenceAdapter((TemplateSequenceModel) model, this);
            }
        }
        // TemplateSequenceModels can be converted to arrays
        if (targetClass.isArray()) {
            if (model instanceof TemplateSequenceModel) {
                return unwrapSequenceToArray((TemplateSequenceModel) model, targetClass, true, recursionStops);
            }
            // array classes are final, no other conversion will work
            return ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS;
        }
        // Allow one-char strings to be coerced to characters
        if (char.class == targetClass || targetClass == Character.class) {
            if (model instanceof TemplateScalarModel) {
                String s = ((TemplateScalarModel) model).getAsString();
                if (s.length() == 1) {
                    return Character.valueOf(s.charAt(0));
                }
            }
            // Character is final, no other conversion will work
            return ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS;
        }
        if (Date.class.isAssignableFrom(targetClass) && model instanceof TemplateDateModel) {
            Date date = ((TemplateDateModel) model).getAsDate();
            if (targetClass.isInstance(date)) {
                return date;
            }
        }
    }
    // End: if (targetClass != Object.class)
    // Since the targetClass was of no help initially, now we use
    // a quite arbitrary order in which we walk through the TemplateModel subinterfaces, and unwrapp them to
    // their "natural" Java correspondent. We still try exclude unwrappings that won't fit the target parameter
    // type(s). This is mostly important because of multi-typed FTL values that could be unwrapped on multiple ways.
    // Iteration's Type Flags. Should be always 0 for non-overloaded and when !is2321Bugfixed.
    int itf = typeFlags;
    // returned, once more with itf == 0. Otherwise we execute this once with itf == 0.
    do {
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_NUMBER) != 0) && model instanceof TemplateNumberModel) {
            Number number = ((TemplateNumberModel) model).getAsNumber();
            if (itf != 0 || targetClass.isInstance(number)) {
                return number;
            }
        }
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_DATE) != 0) && model instanceof TemplateDateModel) {
            Date date = ((TemplateDateModel) model).getAsDate();
            if (itf != 0 || targetClass.isInstance(date)) {
                return date;
            }
        }
        if ((itf == 0 || (itf & (TypeFlags.ACCEPTS_STRING | TypeFlags.CHARACTER)) != 0) && model instanceof TemplateScalarModel && (itf != 0 || targetClass.isAssignableFrom(String.class))) {
            String strVal = ((TemplateScalarModel) model).getAsString();
            if (itf == 0 || (itf & TypeFlags.CHARACTER) == 0) {
                return strVal;
            } else {
                // TypeFlags.CHAR == 1
                if (strVal.length() == 1) {
                    if ((itf & TypeFlags.ACCEPTS_STRING) != 0) {
                        return new CharacterOrString(strVal);
                    } else {
                        return Character.valueOf(strVal.charAt(0));
                    }
                } else if ((itf & TypeFlags.ACCEPTS_STRING) != 0) {
                    return strVal;
                }
            // It had to be unwrapped to Character, but the string length wasn't 1 => Fall through
            }
        }
        // Should be earlier than TemplateScalarModel, but we keep it here until FM 2.4 or such
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_BOOLEAN) != 0) && model instanceof TemplateBooleanModel && (itf != 0 || targetClass.isAssignableFrom(Boolean.class))) {
            return Boolean.valueOf(((TemplateBooleanModel) model).getAsBoolean());
        }
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_MAP) != 0) && model instanceof TemplateHashModel && (itf != 0 || targetClass.isAssignableFrom(HashAdapter.class))) {
            return new HashAdapter((TemplateHashModel) model, this);
        }
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_LIST) != 0) && model instanceof TemplateSequenceModel && (itf != 0 || targetClass.isAssignableFrom(SequenceAdapter.class))) {
            return new SequenceAdapter((TemplateSequenceModel) model, this);
        }
        if ((itf == 0 || (itf & TypeFlags.ACCEPTS_SET) != 0) && model instanceof TemplateCollectionModel && (itf != 0 || targetClass.isAssignableFrom(SetAdapter.class))) {
            return new SetAdapter((TemplateCollectionModel) model, this);
        }
        // enough to check if the TypeFlags.ACCEPTS_ARRAY bit is 1:
        if ((itf & TypeFlags.ACCEPTS_ARRAY) != 0 && model instanceof TemplateSequenceModel) {
            return new SequenceAdapter((TemplateSequenceModel) model, this);
        }
        if (itf == 0) {
            break;
        }
        // start 2nd iteration
        itf = 0;
    } while (true);
    // Note that this will be always true for Object.class targetClass.
    if (targetClass.isInstance(model)) {
        return model;
    }
    return ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS;
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateNumberModel(freemarker.template.TemplateNumberModel) TemplateDateModel(freemarker.template.TemplateDateModel) AdapterTemplateModel(freemarker.template.AdapterTemplateModel) Date(java.util.Date) TemplateHashModel(freemarker.template.TemplateHashModel) Collection(java.util.Collection) AccessibleObject(java.lang.reflect.AccessibleObject) TemplateScalarModel(freemarker.template.TemplateScalarModel) WrapperTemplateModel(freemarker.ext.util.WrapperTemplateModel) TemplateCollectionModel(freemarker.template.TemplateCollectionModel) TemplateBooleanModel(freemarker.template.TemplateBooleanModel)

Aggregations

TemplateDateModel (freemarker.template.TemplateDateModel)3 TemplateNumberModel (freemarker.template.TemplateNumberModel)3 WrapperTemplateModel (freemarker.ext.util.WrapperTemplateModel)1 AdapterTemplateModel (freemarker.template.AdapterTemplateModel)1 TemplateBooleanModel (freemarker.template.TemplateBooleanModel)1 TemplateCollectionModel (freemarker.template.TemplateCollectionModel)1 TemplateHashModel (freemarker.template.TemplateHashModel)1 TemplateScalarModel (freemarker.template.TemplateScalarModel)1 TemplateSequenceModel (freemarker.template.TemplateSequenceModel)1 AccessibleObject (java.lang.reflect.AccessibleObject)1 Collection (java.util.Collection)1 Date (java.util.Date)1