You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/09/25 15:16:10 UTC
[1/4] incubator-freemarker git commit: New built-in,
sequence. This can be used to work around situations where a listable
value lacks some features that you need in the template (like it can't be
listed twice, it can't tell its size, etc.), and you can'
Repository: incubator-freemarker
Updated Branches:
refs/heads/2.3 dd60aef18 -> bdc902508
New built-in, sequence. This can be used to work around situations where a listable value lacks some features that you need in the template (like it can't be listed twice, it can't tell its size, etc.), and you can't modify the data-model to fix the problem. See more...
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/2d0b4931
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/2d0b4931
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/2d0b4931
Branch: refs/heads/2.3
Commit: 2d0b49319a216e610a5aa0ade5dd24ae7881457d
Parents: a671110
Author: ddekany <dd...@apache.org>
Authored: Sun Sep 17 18:28:30 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Sep 17 18:28:30 2017 +0200
----------------------------------------------------------------------
src/main/java/freemarker/core/BuiltIn.java | 4 +-
.../freemarker/core/BuiltInsForSequences.java | 29 +++++++
.../freemarker/core/CollectionAndSequence.java | 11 ++-
.../freemarker/core/NonSequenceException.java | 9 ++-
.../core/UnexpectedTypeException.java | 12 +++
src/manual/en_US/book.xml | 84 ++++++++++++++++++--
.../freemarker/core/SequenceBuiltInTest.java | 82 +++++++++++++++++++
7 files changed, 216 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/main/java/freemarker/core/BuiltIn.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index b4e3239..630f895 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -61,6 +61,7 @@ import freemarker.core.BuiltInsForSequences.lastBI;
import freemarker.core.BuiltInsForSequences.reverseBI;
import freemarker.core.BuiltInsForSequences.seq_containsBI;
import freemarker.core.BuiltInsForSequences.seq_index_ofBI;
+import freemarker.core.BuiltInsForSequences.sequenceBI;
import freemarker.core.BuiltInsForSequences.sortBI;
import freemarker.core.BuiltInsForSequences.sort_byBI;
import freemarker.core.BuiltInsForStringsMisc.evalBI;
@@ -83,7 +84,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
static final Set<String> CAMEL_CASE_NAMES = new TreeSet<String>();
static final Set<String> SNAKE_CASE_NAMES = new TreeSet<String>();
- static final int NUMBER_OF_BIS = 263;
+ static final int NUMBER_OF_BIS = 264;
static final HashMap<String, BuiltIn> BUILT_INS_BY_NAME = new HashMap(NUMBER_OF_BIS * 3 / 2 + 1, 1f);
static {
@@ -262,6 +263,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
putBI("seq_contains", "seqContains", new seq_containsBI());
putBI("seq_index_of", "seqIndexOf", new seq_index_ofBI(true));
putBI("seq_last_index_of", "seqLastIndexOf", new seq_index_ofBI(false));
+ putBI("sequence", new sequenceBI());
putBI("short", new shortBI());
putBI("size", new BuiltInsForMultipleTypes.sizeBI());
putBI("sort_by", "sortBy", new sort_byBI());
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/main/java/freemarker/core/BuiltInsForSequences.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForSequences.java b/src/main/java/freemarker/core/BuiltInsForSequences.java
index 8430133..f2d1c6a 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -30,8 +30,10 @@ import java.util.List;
import freemarker.ext.beans.CollectionModel;
import freemarker.template.SimpleNumber;
import freemarker.template.SimpleScalar;
+import freemarker.template.SimpleSequence;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateCollectionModelEx;
import freemarker.template.TemplateDateModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateHashModel;
@@ -829,6 +831,33 @@ class BuiltInsForSequences {
}
+ static class sequenceBI extends BuiltIn {
+
+ @Override
+ TemplateModel _eval(Environment env) throws TemplateException {
+ TemplateModel model = target.eval(env);
+
+ if (model instanceof TemplateSequenceModel && !isBuggySeqButGoodCollection(model)) {
+ return model;
+ }
+
+ if (!(model instanceof TemplateCollectionModel)) {
+ throw new NonSequenceOrCollectionException(target, model, env);
+ }
+ TemplateCollectionModel coll = (TemplateCollectionModel) model;
+
+ SimpleSequence seq =
+ coll instanceof TemplateCollectionModelEx
+ ? new SimpleSequence(((TemplateCollectionModelEx) coll).size())
+ : new SimpleSequence();
+ for (TemplateModelIterator iter = coll.iterator(); iter.hasNext(); ) {
+ seq.add(iter.next());
+ }
+ return seq;
+ }
+
+ }
+
private static boolean isBuggySeqButGoodCollection(
TemplateModel model) {
return model instanceof CollectionModel
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/main/java/freemarker/core/CollectionAndSequence.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/CollectionAndSequence.java b/src/main/java/freemarker/core/CollectionAndSequence.java
index 79e7576..33556ff 100644
--- a/src/main/java/freemarker/core/CollectionAndSequence.java
+++ b/src/main/java/freemarker/core/CollectionAndSequence.java
@@ -23,6 +23,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateCollectionModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelIterator;
@@ -30,13 +31,13 @@ import freemarker.template.TemplateSequenceModel;
/**
* Add sequence capabilities to an existing collection, or
- * vice versa. Used by ?keys and ?values built-ins.
+ * vice versa. Used by the ?keys and ?values built-ins.
*/
final public class CollectionAndSequence
implements TemplateCollectionModel, TemplateSequenceModel, Serializable {
private TemplateCollectionModel collection;
private TemplateSequenceModel sequence;
- private ArrayList data;
+ private ArrayList<TemplateModel> data;
public CollectionAndSequence(TemplateCollectionModel collection) {
this.collection = collection;
@@ -59,13 +60,15 @@ implements TemplateCollectionModel, TemplateSequenceModel, Serializable {
return sequence.get(i);
} else {
initSequence();
- return (TemplateModel) data.get(i);
+ return data.get(i);
}
}
public int size() throws TemplateModelException {
if (sequence != null) {
return sequence.size();
+ } if (collection instanceof TemplateCollectionModelEx) {
+ return ((TemplateCollectionModelEx) collection).size();
} else {
initSequence();
return data.size();
@@ -74,7 +77,7 @@ implements TemplateCollectionModel, TemplateSequenceModel, Serializable {
private void initSequence() throws TemplateModelException {
if (data == null) {
- data = new ArrayList();
+ data = new ArrayList<TemplateModel>();
TemplateModelIterator it = collection.iterator();
while (it.hasNext()) {
data.add(it.next());
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/main/java/freemarker/core/NonSequenceException.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/NonSequenceException.java b/src/main/java/freemarker/core/NonSequenceException.java
index 2b85ab9..21440bc 100644
--- a/src/main/java/freemarker/core/NonSequenceException.java
+++ b/src/main/java/freemarker/core/NonSequenceException.java
@@ -21,6 +21,7 @@ package freemarker.core;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateSequenceModel;
+import freemarker.template.utility.CollectionUtils;
/**
* Indicates that a {@link TemplateSequenceModel} value was expected, but the value had a different type.
@@ -46,19 +47,19 @@ public class NonSequenceException extends UnexpectedTypeException {
NonSequenceException(
Expression blamed, TemplateModel model, Environment env)
throws InvalidReferenceException {
- super(blamed, model, "sequence", EXPECTED_TYPES, env);
+ this(blamed, model, CollectionUtils.EMPTY_OBJECT_ARRAY, env);
}
NonSequenceException(
Expression blamed, TemplateModel model, String tip,
Environment env)
throws InvalidReferenceException {
- super(blamed, model, "sequence", EXPECTED_TYPES, tip, env);
+ this(blamed, model, new Object[] { tip }, env);
}
NonSequenceException(
- Expression blamed, TemplateModel model, String[] tips, Environment env) throws InvalidReferenceException {
+ Expression blamed, TemplateModel model, Object[] tips, Environment env) throws InvalidReferenceException {
super(blamed, model, "sequence", EXPECTED_TYPES, tips, env);
}
-
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/main/java/freemarker/core/UnexpectedTypeException.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnexpectedTypeException.java b/src/main/java/freemarker/core/UnexpectedTypeException.java
index 0878f81..61b0fe4 100644
--- a/src/main/java/freemarker/core/UnexpectedTypeException.java
+++ b/src/main/java/freemarker/core/UnexpectedTypeException.java
@@ -19,8 +19,13 @@
package freemarker.core;
+import java.util.Arrays;
+
+import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateCollectionModelEx;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
+import freemarker.template.TemplateSequenceModel;
/**
* The type of a value differs from what was expected.
@@ -88,6 +93,13 @@ public class UnexpectedTypeException extends TemplateException {
errorDescBuilder.tip(tip);
}
}
+ if (model instanceof TemplateCollectionModel
+ && (Arrays.asList(expectedTypes).contains(TemplateSequenceModel.class)
+ || Arrays.asList(expectedTypes).contains(TemplateCollectionModelEx.class))) {
+ errorDescBuilder.tip("As the problematic value contains a collection of items, you could convert it "
+ + "to a sequence like someValue?sequence. Be sure though that you won't have a large number of "
+ + "items, as all will be held in memory one the same time.");
+ }
return errorDescBuilder;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 21c3479..569cbac 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -12812,6 +12812,10 @@ grant codeBase "file:/path/to/freemarker.jar"
</listitem>
<listitem>
+ <para><link linkend="ref_builtin_sequence">sequence</link></para>
+ </listitem>
+
+ <listitem>
<para><link linkend="ref_builtin_sort_by">sort_by</link></para>
</listitem>
@@ -18439,6 +18443,61 @@ ${1305575275540?number_to_time}</programlisting>
May 16, 2011
3:47:55 PM</programlisting>
</section>
+
+ <section xml:id="ref_builtin_sequence">
+ <title>sequence</title>
+
+ <indexterm>
+ <primary>seq_sequence built-in</primary>
+ </indexterm>
+
+ <para>This built-in is used to convert a listable value (one that
+ you can iterate through with the <link
+ linkend="ref.directive.list"><literal>list</literal>
+ directive</link>) to a more capable <link
+ linkend="dgui_datamodel_container">sequence</link> value. Sequences
+ support operations like <literal>xs[index]</literal> and
+ <literal>xs?size</literal>. Also, the resulting value is listable
+ for multiple times, even if the original value was backed by a
+ <literal>java.util.Iterator</literal>. This built-in is typically
+ used to work around data-model problems, in case you can't fix the
+ data-model itself. If you can, always fix the data-model instead
+ (give a <literal>java.util.List</literal> or array to the template
+ instead of a more restricted object, like a
+ non-<literal>List</literal> <literal>java.util.Collection</literal>,
+ or a <literal>java.util.Iterator</literal>).</para>
+
+ <para>If the value is already a sequence, then this built-in just
+ returns that as is. If the value is not something that the <link
+ linkend="ref.directive.list"><literal>list</literal>
+ directive</link> could list, then template processing will be
+ aborted with error. Otherwise, it fetches all the values, and stores
+ them into a sequence. Be careful if you can have a huge number of
+ items, as all of them will be held in memory on the same
+ time.</para>
+
+ <para>You should convert a value with <literal>sequence</literal>
+ only once. If you need the resulting sequence at multiple places,
+ always assign the result to a variable, because if the value you
+ convert is only listable once, converting it for the second time
+ will result in error or an empty sequence. Also the conversion is
+ somewhat costly for big collections, so it's better to do it only
+ once.</para>
+
+ <para>Example: Let's say you find that <literal>users</literal> is
+ only listable once (because it's a
+ <literal>java.util.Iterator</literal>), but you need to list it for
+ multiple times in the template, and you can't fix the data-model.
+ Then you could do this:</para>
+
+ <programlisting role="template"><#-- Collect all the users into a sequence: -->
+<#assign usersSeq = users?sequence>
+
+<#list usersSeq as user>...</#list>
+Again:
+<#list usersSeq as user>...</#list>
+</programlisting>
+ </section>
</section>
</chapter>
@@ -18494,6 +18553,11 @@ May 16, 2011
</listitem>
<listitem>
+ <para><link
+ linkend="ref.directive.list.continue">continue</link></para>
+ </listitem>
+
+ <listitem>
<para><link linkend="ref.directive.default">default</link></para>
</listitem>
@@ -26989,11 +27053,10 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
<itemizedlist>
<listitem>
- <para>Added the <link
- linkend="ref.directive.list.continue"><literal>continue</literal>
- directive</link>, which can be used inside a
- <literal>list</literal> to skip to the next iteration (similarly
- as in Java).</para>
+ <para>New directive: <literal>continue</literal>. This can be
+ used inside the <literal>list</literal> directive to skip to the
+ next iteration (similarly as in Java). <link
+ linkend="ref.directive.list.continue">See more...</link></para>
</listitem>
<listitem>
@@ -27010,6 +27073,15 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
</listitem>
<listitem>
+ <para>New built-in, <literal>sequence</literal>. This can be
+ used to work around situations where a listable value lacks some
+ features that you need in the template (like it can't be listed
+ twice, it can't tell its size, etc.), and you can't modify the
+ data-model to fix the problem. <link
+ linkend="ref_builtin_sequence">See more...</link></para>
+ </listitem>
+
+ <listitem>
<para>Bug fixed (<link
xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-70">FREEMARKER-70</link>):
The usage of loop variable built-ins, like
@@ -27033,7 +27105,7 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-71">FREEMARKER-71</link>):
When using
<literal><replaceable>exp</replaceable>?eval</literal>, if the
- expression inside evaluated string throws an exception, the
+ expression inside the evaluated string throws an exception, the
cause exception of that exception was lost.</para>
</listitem>
</itemizedlist>
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/2d0b4931/src/test/java/freemarker/core/SequenceBuiltInTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/SequenceBuiltInTest.java b/src/test/java/freemarker/core/SequenceBuiltInTest.java
new file mode 100644
index 0000000..77eecc5
--- /dev/null
+++ b/src/test/java/freemarker/core/SequenceBuiltInTest.java
@@ -0,0 +1,82 @@
+package freemarker.core;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+import freemarker.template.Configuration;
+import freemarker.template.DefaultIterableAdapter;
+import freemarker.template.DefaultNonListCollectionAdapter;
+import freemarker.template.TemplateCollectionModelEx;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateSequenceModel;
+import freemarker.template.utility.ObjectWrapperWithAPISupport;
+import freemarker.test.TemplateTest;
+
+public class SequenceBuiltInTest extends TemplateTest {
+
+ @Test
+ public void testWithCollection() throws TemplateException, IOException {
+ ObjectWrapperWithAPISupport ow = (ObjectWrapperWithAPISupport) getConfiguration().getObjectWrapper();
+
+ TemplateModel xs = DefaultIterableAdapter.adapt(ImmutableSet.of("a", "b"), ow);
+ assertThat(xs, not(instanceOf(TemplateCollectionModelEx.class)));
+ assertThat(xs, not(instanceOf(TemplateSequenceModel.class)));
+ addToDataModel("xs", xs);
+
+ try {
+ assertOutput("${xs[1]}", "b");
+ fail();
+ } catch (TemplateException e) {
+ System.out.println(e); //!!T
+ assertThat(e.getMessage(), containsString("?sequence")); // Contains tip to use ?sequence
+ }
+ assertOutput("${xs?sequence[1]}", "b");
+
+ try {
+ assertOutput("${xs?size}", "2");
+ fail();
+ } catch (TemplateException e) {
+ System.out.println(e); //!!T
+ assertThat(e.getMessage(), containsString("?sequence")); // Contains tip to use ?sequence
+ }
+ assertOutput("${xs?sequence?size}", "2");
+ }
+
+ @Test
+ public void testWithCollectionEx() throws TemplateException, IOException {
+ ObjectWrapperWithAPISupport ow = (ObjectWrapperWithAPISupport) getConfiguration().getObjectWrapper();
+
+ TemplateModel xs = DefaultNonListCollectionAdapter.adapt(ImmutableSet.of("a", "b"), ow);
+ assertThat(xs, not(instanceOf(TemplateSequenceModel.class)));
+ assertThat(xs, instanceOf(TemplateCollectionModelEx.class));
+ addToDataModel("xs", xs);
+
+ try {
+ assertOutput("${xs[1]}", "b");
+ fail();
+ } catch (TemplateException e) {
+ assertThat(e.getMessage(), containsString("?sequence")); // Contains tip to use ?sequence
+ }
+ assertOutput("${xs?sequence[1]}", "b");
+
+ assertOutput("${xs?size}", "2"); // No need for ?sequence
+ }
+
+ @Test
+ public void testWithSequence() throws TemplateException, IOException {
+ assertOutput("${[11, 12]?sequence[1]}", "12");
+
+
+ getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_23);
+ // As it returns the sequence as is, it works with an infinite sequence:
+ assertOutput("${(11..)?sequence[1]}", "12");
+ }
+
+}
[4/4] incubator-freemarker git commit: Merge remote-tracking branch
'origin/2.3-gae' into 2.3
Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/bdc90250
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/bdc90250
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/bdc90250
Branch: refs/heads/2.3
Commit: bdc902508893c202a1cc370ef6c19a9b18abd16b
Parents: dd60aef b246de2
Author: ddekany <dd...@apache.org>
Authored: Mon Sep 25 17:15:38 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Mon Sep 25 17:15:38 2017 +0200
----------------------------------------------------------------------
.../freemarker/core/ArithmeticExpression.java | 38 +++---
src/main/java/freemarker/core/BuiltIn.java | 4 +-
.../freemarker/core/BuiltInsForSequences.java | 29 +++++
.../freemarker/core/CollectionAndSequence.java | 11 +-
src/main/java/freemarker/core/Configurable.java | 26 ++--
.../freemarker/core/NonSequenceException.java | 9 +-
.../core/UnexpectedTypeException.java | 12 ++
src/manual/en_US/book.xml | 123 ++++++++++++++++---
.../freemarker/core/MiscErrorMessagesTest.java | 11 ++
.../freemarker/core/SequenceBuiltInTest.java | 82 +++++++++++++
.../core/StringLiteralInterpolationTest.java | 2 +-
.../freemarker/template/ConfigurationTest.java | 24 ++++
12 files changed, 322 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
[3/4] incubator-freemarker git commit: Bug fixed (part of
FREEMARKER-48): When an arithmetic exception has occurred in an expression
(typically division by zero),
the template processing has thrown the ArithmeticException as is,
without packaging it into
Posted by dd...@apache.org.
Bug fixed (part of FREEMARKER-48): When an arithmetic exception has occurred in an expression (typically division by zero), the template processing has thrown the ArithmeticException as is, without packaging it into a TemplateException. Thus, the error location in the template wasn't visible in the exception.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/b246de24
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/b246de24
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/b246de24
Branch: refs/heads/2.3
Commit: b246de2403bac5b82c44a83cc3b7ab5b6617d0e8
Parents: ee1e922
Author: ddekany <dd...@apache.org>
Authored: Mon Sep 18 22:49:56 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Mon Sep 18 22:49:56 2017 +0200
----------------------------------------------------------------------
.../freemarker/core/ArithmeticExpression.java | 38 +++++++++++---------
src/manual/en_US/book.xml | 11 ++++++
.../freemarker/core/MiscErrorMessagesTest.java | 11 ++++++
.../core/StringLiteralInterpolationTest.java | 2 +-
4 files changed, 45 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b246de24/src/main/java/freemarker/core/ArithmeticExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ArithmeticExpression.java b/src/main/java/freemarker/core/ArithmeticExpression.java
index 4fbe778..2ed7890 100644
--- a/src/main/java/freemarker/core/ArithmeticExpression.java
+++ b/src/main/java/freemarker/core/ArithmeticExpression.java
@@ -54,22 +54,28 @@ final class ArithmeticExpression extends Expression {
static TemplateModel _eval(Environment env, TemplateObject parent, Number lhoNumber, int operator, Number rhoNumber)
throws TemplateException, _MiscTemplateException {
ArithmeticEngine ae = EvalUtil.getArithmeticEngine(env, parent);
- switch (operator) {
- case TYPE_SUBSTRACTION :
- return new SimpleNumber(ae.subtract(lhoNumber, rhoNumber));
- case TYPE_MULTIPLICATION :
- return new SimpleNumber(ae.multiply(lhoNumber, rhoNumber));
- case TYPE_DIVISION :
- return new SimpleNumber(ae.divide(lhoNumber, rhoNumber));
- case TYPE_MODULO :
- return new SimpleNumber(ae.modulus(lhoNumber, rhoNumber));
- default:
- if (parent instanceof Expression) {
- throw new _MiscTemplateException((Expression) parent,
- "Unknown operation: ", Integer.valueOf(operator));
- } else {
- throw new _MiscTemplateException("Unknown operation: ", Integer.valueOf(operator));
- }
+ try {
+ switch (operator) {
+ case TYPE_SUBSTRACTION :
+ return new SimpleNumber(ae.subtract(lhoNumber, rhoNumber));
+ case TYPE_MULTIPLICATION :
+ return new SimpleNumber(ae.multiply(lhoNumber, rhoNumber));
+ case TYPE_DIVISION :
+ return new SimpleNumber(ae.divide(lhoNumber, rhoNumber));
+ case TYPE_MODULO :
+ return new SimpleNumber(ae.modulus(lhoNumber, rhoNumber));
+ default:
+ if (parent instanceof Expression) {
+ throw new _MiscTemplateException((Expression) parent,
+ "Unknown operation: ", Integer.valueOf(operator));
+ } else {
+ throw new _MiscTemplateException("Unknown operation: ", Integer.valueOf(operator));
+ }
+ }
+ } catch (ArithmeticException e) {
+ throw new _MiscTemplateException(e, env,
+ "Arithmetic operation failed",
+ (e.getMessage() != null ? new String[] { ": ", e.getMessage() } : " (see cause exception)"));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b246de24/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 210f674..edb158b 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -27179,6 +27179,17 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
</listitem>
<listitem>
+ <para>Bug fixed (part of <link
+ xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-48">FREEMARKER-48</link>):
+ When an arithmetic exception has occurred in an expression
+ (typically division by zero), the template processing has thrown
+ the <literal>ArithmeticException</literal> as is, without
+ packaging it into a <literal>TemplateException</literal>. Thus,
+ the error location in the template wasn't visible in the
+ exception.</para>
+ </listitem>
+
+ <listitem>
<para>When logging error due to an error in an <link
linkend="ref.directive.attempt"><literal>attempt</literal>
directive</link> block, the log message now indicates that the
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b246de24/src/test/java/freemarker/core/MiscErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/MiscErrorMessagesTest.java b/src/test/java/freemarker/core/MiscErrorMessagesTest.java
index 79ccb2c..5799c12 100644
--- a/src/test/java/freemarker/core/MiscErrorMessagesTest.java
+++ b/src/test/java/freemarker/core/MiscErrorMessagesTest.java
@@ -19,9 +19,13 @@
package freemarker.core;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
import org.junit.Test;
import freemarker.cache.TemplateNameFormat;
+import freemarker.template.TemplateException;
import freemarker.test.TemplateTest;
public class MiscErrorMessagesTest extends TemplateTest {
@@ -45,4 +49,11 @@ public class MiscErrorMessagesTest extends TemplateTest {
assertErrorContains("${{}[10]}", "[]", "?api");
}
+ @Test
+ public void aritheticException() {
+ Throwable e = assertErrorContains("<#assign x = 0>\n${1 / x}", "Arithmetic");
+ assertThat(e, instanceOf(TemplateException.class));
+ assertEquals((Integer) 2, ((TemplateException) e).getLineNumber());
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b246de24/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
index b0d0581..f655865 100644
--- a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
@@ -80,7 +80,7 @@ public class StringLiteralInterpolationTest extends TemplateTest {
public void testErrors() {
addToDataModel("x", 1);
assertErrorContains("${'${noSuchVar}'}", InvalidReferenceException.class, "missing", "noSuchVar");
- assertErrorContains("${'${x/0}'}", ArithmeticException.class, "zero");
+ assertErrorContains("${'${x/0}'}", "zero");
}
@Test
[2/4] incubator-freemarker git commit: Bug fixed: When setting the
new_builtin_resolver from Properties or the setSetting(String, String) API,
it didn't recognize the camel case form of the allowed_classes and
trusted_templates keywords, and throw except
Posted by dd...@apache.org.
Bug fixed: When setting the new_builtin_resolver from Properties or the setSetting(String, String) API, it didn't recognize the camel case form of the allowed_classes and trusted_templates keywords, and throw exception for them. Now allowedClasses and trustedTemplates can be used as well.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/ee1e9221
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/ee1e9221
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/ee1e9221
Branch: refs/heads/2.3
Commit: ee1e9221a8c6ed41a07cb0df80c2cbad608ea5b6
Parents: 2d0b493
Author: ddekany <dd...@apache.org>
Authored: Mon Sep 18 13:15:33 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Mon Sep 18 13:15:33 2017 +0200
----------------------------------------------------------------------
src/main/java/freemarker/core/Configurable.java | 26 +++++++++++-------
src/manual/en_US/book.xml | 28 ++++++++++++++------
.../freemarker/template/ConfigurationTest.java | 24 +++++++++++++++++
3 files changed, 61 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ee1e9221/src/main/java/freemarker/core/Configurable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index 492282a..0ae1be4 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -2033,8 +2033,10 @@ public class Configurable {
}
}
- private static final String ALLOWED_CLASSES = "allowed_classes";
- private static final String TRUSTED_TEMPLATES = "trusted_templates";
+ private static final String ALLOWED_CLASSES_SNAKE_CASE = "allowed_classes";
+ private static final String TRUSTED_TEMPLATES_SNAKE_CASE = "trusted_templates";
+ private static final String ALLOWED_CLASSES_CAMEL_CASE = "allowedClasses";
+ private static final String TRUSTED_TEMPLATES_CAMEL_CASE = "trustedTemplates";
/**
* Sets a FreeMarker setting by a name and string value. If you can configure FreeMarker directly with Java (or
@@ -2179,13 +2181,13 @@ public class Configurable {
* Use {@link TemplateClassResolver#UNRESTRICTED_RESOLVER}
* <li><p>{@code "safer"}:
* Use {@link TemplateClassResolver#SAFER_RESOLVER}
- * <li><p>{@code "allows_nothing"}:
+ * <li><p>{@code "allows_nothing"} (or {@code "allowsNothing"}):
* Use {@link TemplateClassResolver#ALLOWS_NOTHING_RESOLVER}
* <li><p>Something that contains colon will use
* {@link OptInTemplateClassResolver} and is expected to
* store comma separated values (possibly quoted) segmented
- * with {@code "allowed_classes:"} and/or
- * {@code "trusted_templates:"}. Examples of valid values:
+ * with {@code "allowed_classes:"} (or {@code "allowedClasses:"}) and/or
+ * {@code "trusted_templates:"} (or {@code "trustedTemplates:"}). Examples of valid values:
*
* <table style="width: auto; border-collapse: collapse" border="1"
* summary="trusted_template value examples">
@@ -2610,15 +2612,21 @@ public class Configurable {
KeyValuePair kv = (KeyValuePair) segments.get(i);
String segmentKey = (String) kv.getKey();
List segmentValue = (List) kv.getValue();
- if (segmentKey.equals(ALLOWED_CLASSES)) {
+ if (segmentKey.equals(ALLOWED_CLASSES_SNAKE_CASE)
+ || segmentKey.equals(ALLOWED_CLASSES_CAMEL_CASE)) {
allowedClasses = new HashSet(segmentValue);
- } else if (segmentKey.equals(TRUSTED_TEMPLATES)) {
+ } else if (segmentKey.equals(TRUSTED_TEMPLATES_SNAKE_CASE)
+ || segmentKey.equals(TRUSTED_TEMPLATES_CAMEL_CASE)) {
trustedTemplates = segmentValue;
} else {
throw new ParseException(
"Unrecognized list segment key: " + StringUtil.jQuote(segmentKey) +
- ". Supported keys are: \"" + ALLOWED_CLASSES + "\", \"" +
- TRUSTED_TEMPLATES + "\"", 0, 0);
+ ". Supported keys are: " +
+ "\"" + ALLOWED_CLASSES_SNAKE_CASE + "\", " +
+ "\"" + ALLOWED_CLASSES_CAMEL_CASE + "\", " +
+ "\"" + TRUSTED_TEMPLATES_SNAKE_CASE + "\", " +
+ "\"" + TRUSTED_TEMPLATES_CAMEL_CASE + "\". ",
+ 0, 0);
}
}
setNewBuiltinClassResolver(
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ee1e9221/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 569cbac..210f674 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -27181,24 +27181,36 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
<listitem>
<para>When logging error due to an error in an <link
linkend="ref.directive.attempt"><literal>attempt</literal>
- directive</link> block, the log message now indicates that error
- was inside an <literal>attempt</literal> block.</para>
+ directive</link> block, the log message now indicates that the
+ error was inside an <literal>attempt</literal> block.</para>
</listitem>
<listitem>
<para>Bug fixed (<link
xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-52">FREEMARKER-52</link>):
- When setting the <literal>output_format</literal> with
- <literal>Properties</literal>, the
- <literal>XHTMLOutputFormat</literal> abbreviation wasn't
- recognized (for example in a <literal>.properties</literal>
- file, <literal>output_format=XHTMLOutputFormat</literal> didn't
- work, only
+ When setting the <literal>output_format</literal> from
+ <literal>Properties</literal> or the <literal>setSetting(String,
+ String)</literal> API, the <literal>XHTMLOutputFormat</literal>
+ abbreviation wasn't recognized (for example in a
+ <literal>.properties</literal> file,
+ <literal>output_format=XHTMLOutputFormat</literal> didn't work,
+ only
<literal>output_format=freemarker.core.XHTMLOutputFormat()</literal>
did).</para>
</listitem>
<listitem>
+ <para>Bug fixed: When setting the
+ <literal>new_builtin_resolver</literal> from
+ <literal>Properties</literal> or the <literal>setSetting(String,
+ String)</literal> API, it didn't recognize the camel case form
+ of the <literal>allowed_classes</literal> and
+ <literal>trusted_templates</literal> keywords, and throw
+ exception for them. Now <literal>allowedClasses</literal> and
+ <literal>trustedTemplates</literal> can be used as well.</para>
+ </listitem>
+
+ <listitem>
<para><literal>Constants.EMPTY_HASH</literal> and
<literal>GeneralPurposeNothing</literal> (the value of
<literal>missingVar!</literal>) now implements
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ee1e9221/src/test/java/freemarker/template/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 226306f..69eaf3a 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -66,9 +66,11 @@ import freemarker.core.EpochMillisTemplateDateFormatFactory;
import freemarker.core.HTMLOutputFormat;
import freemarker.core.HexTemplateNumberFormatFactory;
import freemarker.core.MarkupOutputFormat;
+import freemarker.core.OptInTemplateClassResolver;
import freemarker.core.OutputFormat;
import freemarker.core.ParseException;
import freemarker.core.RTFOutputFormat;
+import freemarker.core.TemplateClassResolver;
import freemarker.core.TemplateDateFormatFactory;
import freemarker.core.TemplateNumberFormatFactory;
import freemarker.core.UndefinedOutputFormat;
@@ -1694,6 +1696,28 @@ public class ConfigurationTest extends TestCase {
assertTrue(cfg.isTimeZoneExplicitlySet());
}
+ public void testNewBuiltinClassResolverSetting() throws TemplateException {
+ Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+ assertSame(TemplateClassResolver.UNRESTRICTED_RESOLVER, cfg.getNewBuiltinClassResolver());
+
+ cfg.setSetting(Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE,
+ "allowed_classes: com.example.C1, com.example.C2, trusted_templates: lib/*, safe.ftl");
+ assertThat(cfg.getNewBuiltinClassResolver(), instanceOf(OptInTemplateClassResolver.class));
+
+ cfg.setSetting(Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE, "safer");
+ assertSame(TemplateClassResolver.SAFER_RESOLVER, cfg.getNewBuiltinClassResolver());
+
+ cfg.setSetting(Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY_CAMEL_CASE,
+ "allowedClasses: com.example.C1, com.example.C2, trustedTemplates: lib/*, safe.ftl");
+ assertThat(cfg.getNewBuiltinClassResolver(), instanceOf(OptInTemplateClassResolver.class));
+
+ cfg.setSetting(Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE, "allowsNothing");
+ assertSame(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER, cfg.getNewBuiltinClassResolver());
+
+ cfg.setSetting(Configuration.NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE, "allows_nothing");
+ assertSame(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER, cfg.getNewBuiltinClassResolver());
+ }
+
@Test
public void testGetSettingNamesAreSorted() throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);