Search in sources :

Example 16 with TemplateSequenceModel

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

the class Environment method invokeNodeHandlerFor.

/**
 * Used for {@code #visit} and {@code #recurse}.
 */
void invokeNodeHandlerFor(TemplateNodeModel node, TemplateSequenceModel namespaces) throws TemplateException, IOException {
    if (nodeNamespaces == null) {
        SimpleSequence ss = new SimpleSequence(1);
        ss.add(currentNamespace);
        nodeNamespaces = ss;
    }
    int prevNodeNamespaceIndex = this.nodeNamespaceIndex;
    String prevNodeName = this.currentNodeName;
    String prevNodeNS = this.currentNodeNS;
    TemplateSequenceModel prevNodeNamespaces = nodeNamespaces;
    TemplateNodeModel prevVisitorNode = currentVisitorNode;
    currentVisitorNode = node;
    if (namespaces != null) {
        this.nodeNamespaces = namespaces;
    }
    try {
        TemplateModel macroOrTransform = getNodeProcessor(node);
        if (macroOrTransform instanceof Macro) {
            invoke((Macro) macroOrTransform, null, null, null, null);
        } else if (macroOrTransform instanceof TemplateTransformModel) {
            visitAndTransform(null, (TemplateTransformModel) macroOrTransform, null);
        } else {
            String nodeType = node.getNodeType();
            if (nodeType != null) {
                // If the node's type is 'text', we just output it.
                if ((nodeType.equals("text") && node instanceof TemplateScalarModel)) {
                    out.write(((TemplateScalarModel) node).getAsString());
                } else if (nodeType.equals("document")) {
                    recurse(node, namespaces);
                } else // we just ignore it.
                if (!nodeType.equals("pi") && !nodeType.equals("comment") && !nodeType.equals("document_type")) {
                    throw new _MiscTemplateException(this, noNodeHandlerDefinedDescription(node, node.getNodeNamespace(), nodeType));
                }
            } else {
                throw new _MiscTemplateException(this, noNodeHandlerDefinedDescription(node, node.getNodeNamespace(), "default"));
            }
        }
    } finally {
        this.currentVisitorNode = prevVisitorNode;
        this.nodeNamespaceIndex = prevNodeNamespaceIndex;
        this.currentNodeName = prevNodeName;
        this.currentNodeNS = prevNodeNS;
        this.nodeNamespaces = prevNodeNamespaces;
    }
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateNodeModel(freemarker.template.TemplateNodeModel) TemplateTransformModel(freemarker.template.TemplateTransformModel) TemplateScalarModel(freemarker.template.TemplateScalarModel) TemplateModel(freemarker.template.TemplateModel) SimpleSequence(freemarker.template.SimpleSequence)

Example 17 with TemplateSequenceModel

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

the class Interpret method calculateResult.

/**
 * Constructs a template on-the-fly and returns it embedded in a
 * {@link TemplateTransformModel}.
 *
 * <p>The built-in has two arguments:
 * the arguments passed to the method. It can receive at
 * least one and at most two arguments, both must evaluate to a scalar.
 * The first scalar is interpreted as a template source code and a template
 * is built from it. The second (optional) is used to give the generated
 * template a name.
 *
 * @return a {@link TemplateTransformModel} that when executed inside
 * a <tt>&lt;transform></tt> block will process the generated template
 * just as if it had been <tt>&lt;transform></tt>-ed at that point.
 */
@Override
protected TemplateModel calculateResult(Environment env) throws TemplateException {
    TemplateModel model = target.eval(env);
    Expression sourceExpr = null;
    String id = "anonymous_interpreted";
    if (model instanceof TemplateSequenceModel) {
        sourceExpr = ((Expression) new DynamicKeyName(target, new NumberLiteral(Integer.valueOf(0))).copyLocationFrom(target));
        if (((TemplateSequenceModel) model).size() > 1) {
            id = ((Expression) new DynamicKeyName(target, new NumberLiteral(Integer.valueOf(1))).copyLocationFrom(target)).evalAndCoerceToPlainText(env);
        }
    } else if (model instanceof TemplateScalarModel) {
        sourceExpr = target;
    } else {
        throw new UnexpectedTypeException(target, model, "sequence or string", new Class[] { TemplateSequenceModel.class, TemplateScalarModel.class }, env);
    }
    String templateSource = sourceExpr.evalAndCoerceToPlainText(env);
    Template parentTemplate = env.getConfiguration().getIncompatibleImprovements().intValue() >= _TemplateAPI.VERSION_INT_2_3_26 ? env.getCurrentTemplate() : env.getTemplate();
    final Template interpretedTemplate;
    try {
        ParserConfiguration pCfg = parentTemplate.getParserConfiguration();
        // pCfg.outputFormat is exceptional: it's inherited from the lexical context
        if (pCfg.getOutputFormat() != outputFormat) {
            pCfg = new _ParserConfigurationWithInheritedFormat(pCfg, outputFormat, Integer.valueOf(autoEscapingPolicy));
        }
        interpretedTemplate = new Template((parentTemplate.getName() != null ? parentTemplate.getName() : "nameless_template") + "->" + id, null, new StringReader(templateSource), parentTemplate.getConfiguration(), pCfg, null);
    } catch (IOException e) {
        throw new _MiscTemplateException(this, e, env, new Object[] { "Template parsing with \"?", key, "\" has failed with this error:\n\n", _MessageUtil.EMBEDDED_MESSAGE_BEGIN, new _DelayedGetMessage(e), _MessageUtil.EMBEDDED_MESSAGE_END, "\n\nThe failed expression:" });
    }
    interpretedTemplate.setLocale(env.getLocale());
    return new TemplateProcessorModel(interpretedTemplate);
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateModel(freemarker.template.TemplateModel) IOException(java.io.IOException) Template(freemarker.template.Template) StringReader(java.io.StringReader) TemplateScalarModel(freemarker.template.TemplateScalarModel)

Example 18 with TemplateSequenceModel

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

the class VisitNode method accept.

@Override
TemplateElement[] accept(Environment env) throws IOException, TemplateException {
    TemplateModel node = targetNode.eval(env);
    if (!(node instanceof TemplateNodeModel)) {
        throw new NonNodeException(targetNode, node, env);
    }
    TemplateModel nss = namespaces == null ? null : namespaces.eval(env);
    if (namespaces instanceof StringLiteral) {
        nss = env.importLib(((TemplateScalarModel) nss).getAsString(), null);
    } else if (namespaces instanceof ListLiteral) {
        nss = ((ListLiteral) namespaces).evaluateStringsToNamespaces(env);
    }
    if (nss != null) {
        if (nss instanceof Environment.Namespace) {
            SimpleSequence ss = new SimpleSequence(1);
            ss.add(nss);
            nss = ss;
        } else if (!(nss instanceof TemplateSequenceModel)) {
            if (namespaces != null) {
                throw new NonSequenceException(namespaces, nss, env);
            } else {
                // Should not occur
                throw new _MiscTemplateException(env, "Expecting a sequence of namespaces after \"using\"");
            }
        }
    }
    env.invokeNodeHandlerFor((TemplateNodeModel) node, (TemplateSequenceModel) nss);
    return null;
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateNodeModel(freemarker.template.TemplateNodeModel) TemplateScalarModel(freemarker.template.TemplateScalarModel) TemplateModel(freemarker.template.TemplateModel) SimpleSequence(freemarker.template.SimpleSequence)

Example 19 with TemplateSequenceModel

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

the class RecurseNode method accept.

@Override
TemplateElement[] accept(Environment env) throws IOException, TemplateException {
    TemplateModel node = targetNode == null ? null : targetNode.eval(env);
    if (node != null && !(node instanceof TemplateNodeModel)) {
        throw new NonNodeException(targetNode, node, "node", env);
    }
    TemplateModel nss = namespaces == null ? null : namespaces.eval(env);
    if (namespaces instanceof StringLiteral) {
        nss = env.importLib(((TemplateScalarModel) nss).getAsString(), null);
    } else if (namespaces instanceof ListLiteral) {
        nss = ((ListLiteral) namespaces).evaluateStringsToNamespaces(env);
    }
    if (nss != null) {
        if (nss instanceof TemplateHashModel) {
            SimpleSequence ss = new SimpleSequence(1);
            ss.add(nss);
            nss = ss;
        } else if (!(nss instanceof TemplateSequenceModel)) {
            if (namespaces != null) {
                throw new NonSequenceException(namespaces, nss, env);
            } else {
                // Should not occur
                throw new _MiscTemplateException(env, "Expecting a sequence of namespaces after \"using\"");
            }
        }
    }
    env.recurse((TemplateNodeModel) node, (TemplateSequenceModel) nss);
    return null;
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateHashModel(freemarker.template.TemplateHashModel) TemplateNodeModel(freemarker.template.TemplateNodeModel) TemplateScalarModel(freemarker.template.TemplateScalarModel) TemplateModel(freemarker.template.TemplateModel) SimpleSequence(freemarker.template.SimpleSequence)

Example 20 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel 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

TemplateSequenceModel (freemarker.template.TemplateSequenceModel)21 TemplateScalarModel (freemarker.template.TemplateScalarModel)9 TemplateModel (freemarker.template.TemplateModel)8 TemplateHashModel (freemarker.template.TemplateHashModel)7 SimpleSequence (freemarker.template.SimpleSequence)6 TemplateNodeModel (freemarker.template.TemplateNodeModel)6 SimpleScalar (freemarker.template.SimpleScalar)5 TemplateNumberModel (freemarker.template.TemplateNumberModel)4 TemplateModelException (freemarker.template.TemplateModelException)3 Test (org.junit.Test)3 TemplateMethodModelEx (freemarker.template.TemplateMethodModelEx)2 TemplateTransformModel (freemarker.template.TemplateTransformModel)2 IOException (java.io.IOException)2 AccessibleObject (java.lang.reflect.AccessibleObject)2 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableListMultimap (com.google.common.collect.ImmutableListMultimap)1 freemarker.core._TemplateModelException (freemarker.core._TemplateModelException)1 DebugModel (freemarker.debug.DebugModel)1 WrapperTemplateModel (freemarker.ext.util.WrapperTemplateModel)1 AdapterTemplateModel (freemarker.template.AdapterTemplateModel)1