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;
}
}
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><transform></tt> block will process the generated template
* just as if it had been <tt><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);
}
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;
}
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;
}
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;
}
Aggregations