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/01 18:58:23 UTC
[4/6] incubator-freemarker git commit: Reworked list/iterable-like
TemplateModel interfaced. Now we have TemplateIterableModel (which is like
TemplateCollectionModel in FM2),
TemplateCollectionModel (which similar to TemplateCollectionModelEx in FM2)
tha
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
index e36d767..c28b385 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
@@ -31,16 +31,16 @@ import java.util.Date;
import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateDateModel;
import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.CollectionAndSequence;
+import org.apache.freemarker.core.model.TemplateStringModel;
+import org.apache.freemarker.core.model.impl.SequenceTemplateModelIterator;
import org.apache.freemarker.core.model.impl.SimpleNumber;
import org.apache.freemarker.core.model.impl.SimpleString;
import org.apache.freemarker.core.model.impl.TemplateModelListSequence;
@@ -48,7 +48,7 @@ import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util._StringUtils;
/**
- * A holder for builtins that operate exclusively on sequence or collection left-hand value.
+ * A holder for builtins that operate on sequence (or some even on iterable) left-hand value.
*/
class BuiltInsForSequences {
@@ -66,7 +66,9 @@ class BuiltInsForSequences {
public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException {
int chunkSize = getNumberArgument(args, 0, this).intValue();
-
+ if (chunkSize < 1) {
+ newArgumentValueException(0, "The value must be at least 1", this);
+ }
return new ChunkedSequence(tsm, chunkSize, args[1]);
}
@@ -89,19 +91,16 @@ class BuiltInsForSequences {
private ChunkedSequence(
TemplateSequenceModel wrappedTsm, int chunkSize, TemplateModel fillerItem)
throws TemplateException {
- if (chunkSize < 1) {
- throw new TemplateException("The 1st argument to ?', key, ' (...) must be at least 1.");
- }
this.wrappedTsm = wrappedTsm;
this.chunkSize = chunkSize;
this.fillerItem = fillerItem;
- numberOfChunks = (wrappedTsm.size() + chunkSize - 1) / chunkSize;
+ numberOfChunks = (wrappedTsm.getCollectionSize() + chunkSize - 1) / chunkSize;
}
@Override
public TemplateModel get(final int chunkIndex)
throws TemplateException {
- if (chunkIndex >= numberOfChunks) {
+ if (chunkIndex >= numberOfChunks || chunkIndex < 0) {
return null;
}
@@ -110,33 +109,51 @@ class BuiltInsForSequences {
private final int baseIndex = chunkIndex * chunkSize;
@Override
- public TemplateModel get(int relIndex)
- throws TemplateException {
+ public TemplateModel get(int relIndex) throws TemplateException {
+ if (relIndex < 0) {
+ return null;
+ }
int absIndex = baseIndex + relIndex;
- if (absIndex < wrappedTsm.size()) {
+ if (absIndex < wrappedTsm.getCollectionSize()) {
return wrappedTsm.get(absIndex);
} else {
- return absIndex < numberOfChunks * chunkSize
- ? fillerItem
- : null;
+ return absIndex < numberOfChunks * chunkSize ? fillerItem : null;
}
}
@Override
- public int size() throws TemplateException {
+ public int getCollectionSize() throws TemplateException {
return fillerItem != null || chunkIndex + 1 < numberOfChunks
? chunkSize
- : wrappedTsm.size() - baseIndex;
+ : wrappedTsm.getCollectionSize() - baseIndex;
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return getCollectionSize() == 0;
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new SequenceTemplateModelIterator(this);
}
-
};
}
@Override
- public int size() throws TemplateException {
+ public int getCollectionSize() throws TemplateException {
return numberOfChunks;
}
-
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return numberOfChunks == 0;
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new SequenceTemplateModelIterator(this);
+ }
}
@Override
@@ -146,56 +163,27 @@ class BuiltInsForSequences {
}
- static class firstBI extends ASTExpBuiltIn {
+ static class firstBI extends BuiltInForIterable {
@Override
- TemplateModel _eval(Environment env)
- throws TemplateException {
- TemplateModel model = target.eval(env);
- // In 2.3.x only, we prefer TemplateSequenceModel for
- // backward compatibility. In 2.4.x, we prefer TemplateCollectionModel.
- if (model instanceof TemplateSequenceModel) {
- return calculateResultForSequence((TemplateSequenceModel) model);
- } else if (model instanceof TemplateCollectionModel) {
- return calculateResultForColletion((TemplateCollectionModel) model);
- } else {
- throw MessageUtils.newUnexpectedOperandTypeException(
- target, model,
- MessageUtils.SEQUENCE_OR_COLLECTION,
- MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
- null, env);
- }
- }
-
- private TemplateModel calculateResultForSequence(TemplateSequenceModel seq)
- throws TemplateException {
- if (seq.size() == 0) {
- return null;
- }
- return seq.get(0);
- }
-
- private TemplateModel calculateResultForColletion(TemplateCollectionModel coll)
- throws TemplateException {
- TemplateModelIterator iter = coll.iterator();
+ TemplateModel calculateResult(TemplateIterableModel model) throws TemplateException {
+ TemplateModelIterator iter = model.iterator();
if (!iter.hasNext()) {
return null;
}
return iter.next();
}
-
+
}
- static class joinBI extends ASTExpBuiltIn {
+ static class joinBI extends BuiltInForIterable {
- private class BIMethodForCollection extends BuiltInCallableImpl implements TemplateFunctionModel {
+ private class BIMethodForIterable extends BuiltInCallableImpl implements TemplateFunctionModel {
- private final Environment env;
- private final TemplateCollectionModel coll;
+ private final TemplateIterableModel iterable;
- private BIMethodForCollection(Environment env, TemplateCollectionModel coll) {
- this.env = env;
- this.coll = coll;
+ private BIMethodForIterable(TemplateIterableModel iterable) {
+ this.iterable = iterable;
}
@Override
@@ -207,7 +195,7 @@ class BuiltInsForSequences {
StringBuilder sb = new StringBuilder();
- TemplateModelIterator it = coll.iterator();
+ TemplateModelIterator it = iterable.iterator();
int idx = 0;
boolean hadItem = false;
@@ -247,23 +235,12 @@ class BuiltInsForSequences {
}
@Override
- TemplateModel _eval(Environment env) throws TemplateException {
- TemplateModel model = target.eval(env);
- if (model instanceof TemplateCollectionModel) {
- if (model instanceof RightUnboundedRangeModel) {
- throw new TemplateException(
- "The sequence to join was right-unbounded numerical range, thus it's infinitely long.");
- }
- return new BIMethodForCollection(env, (TemplateCollectionModel) model);
- } else if (model instanceof TemplateSequenceModel) {
- return new BIMethodForCollection(env, new CollectionAndSequence((TemplateSequenceModel) model));
- } else {
- throw MessageUtils.newUnexpectedOperandTypeException(
- target, model,
- MessageUtils.SEQUENCE_OR_COLLECTION,
- MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
- null, env);
+ TemplateModel calculateResult(TemplateIterableModel model) throws TemplateException {
+ if (model instanceof RightUnboundedRangeModel) {
+ throw new TemplateException(
+ "The sequence to join was right-unbounded numerical range, thus it's infinitely long.");
}
+ return new BIMethodForIterable((TemplateIterableModel) model);
}
}
@@ -272,10 +249,11 @@ class BuiltInsForSequences {
@Override
TemplateModel calculateResult(TemplateSequenceModel tsm)
throws TemplateException {
- if (tsm.size() == 0) {
+ int size = tsm.getCollectionSize();
+ if (size == 0) {
return null;
}
- return tsm.get(tsm.size() - 1);
+ return tsm.get(size - 1);
}
}
@@ -289,12 +267,22 @@ class BuiltInsForSequences {
@Override
public TemplateModel get(int index) throws TemplateException {
- return seq.get(seq.size() - 1 - index);
+ return seq.get(seq.getCollectionSize() - 1 - index);
+ }
+
+ @Override
+ public int getCollectionSize() throws TemplateException {
+ return seq.getCollectionSize();
}
@Override
- public int size() throws TemplateException {
- return seq.size();
+ public boolean isEmptyCollection() throws TemplateException {
+ return seq.isEmptyCollection();
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new SequenceTemplateModelIterator(this);
}
}
@@ -308,25 +296,24 @@ class BuiltInsForSequences {
}
}
- static class seq_containsBI extends ASTExpBuiltIn {
- private class BIMethodForCollection extends BuiltInCallableImpl implements TemplateFunctionModel {
- private TemplateCollectionModel m_coll;
- private Environment m_env;
+ static class seq_containsBI extends BuiltInForIterable {
+ private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
+ private TemplateIterableModel iterable;
- private BIMethodForCollection(TemplateCollectionModel coll, Environment env) {
- m_coll = coll;
- m_env = env;
+ private BIMethod(TemplateIterableModel coll) {
+ iterable = coll;
}
@Override
public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException {
TemplateModel arg = args[0];
- TemplateModelIterator it = m_coll.iterator();
+ TemplateModelIterator it = iterable.iterator();
int idx = 0;
while (it.hasNext()) {
- if (modelsEqual(idx, it.next(), arg, m_env))
+ if (modelsEqual(idx, it.next(), arg, env)) {
return TemplateBooleanModel.TRUE;
+ }
idx++;
}
return TemplateBooleanModel.FALSE;
@@ -339,111 +326,38 @@ class BuiltInsForSequences {
}
- private class BIMethodForSequence extends BuiltInCallableImpl implements TemplateFunctionModel {
- private TemplateSequenceModel m_seq;
- private Environment m_env;
-
- private BIMethodForSequence(TemplateSequenceModel seq, Environment env) {
- m_seq = seq;
- m_env = env;
- }
-
- @Override
- public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
- throws TemplateException {
- TemplateModel arg = args[0];
- int size = m_seq.size();
- for (int i = 0; i < size; i++) {
- if (modelsEqual(i, m_seq.get(i), arg, m_env))
- return TemplateBooleanModel.TRUE;
- }
- return TemplateBooleanModel.FALSE;
- }
-
- @Override
- public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
- return ArgumentArrayLayout.SINGLE_POSITIONAL_PARAMETER;
- }
-
- }
-
@Override
- TemplateModel _eval(Environment env)
- throws TemplateException {
- TemplateModel model = target.eval(env);
- // In 2.3.x only, we prefer TemplateSequenceModel for
- // backward compatibility. In 2.4.x, we prefer TemplateCollectionModel.
- if (model instanceof TemplateSequenceModel) {
- return new BIMethodForSequence((TemplateSequenceModel) model, env);
- } else if (model instanceof TemplateCollectionModel) {
- return new BIMethodForCollection((TemplateCollectionModel) model, env);
- } else {
- throw MessageUtils.newUnexpectedOperandTypeException(
- target, model,
- MessageUtils.SEQUENCE_OR_COLLECTION,
- MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
- null, env);
- }
+ TemplateModel calculateResult(TemplateIterableModel model) throws TemplateException {
+ return new BIMethod((TemplateIterableModel) model);
}
}
- static class seq_index_ofBI extends ASTExpBuiltIn {
+ static class seq_index_ofBI extends BuiltInForIterable {
private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
- final TemplateSequenceModel m_seq;
- final TemplateCollectionModel m_col;
- final Environment m_env;
+ final TemplateIterableModel iterable;
- private BIMethod(Environment env)
+ private BIMethod(TemplateIterableModel iterable)
throws TemplateException {
- TemplateModel model = target.eval(env);
- m_seq = model instanceof TemplateSequenceModel
- ? (TemplateSequenceModel) model
- : null;
- // [FM3] Rework the below
- // In 2.3.x only, we deny the possibility of collection
- // access if there's sequence access. This is so to minimize
- // the change of compatibility issues; without this, objects
- // that implement both the sequence and collection interfaces
- // would suddenly start using the collection interface, and if
- // that's buggy that would surface now, breaking the application
- // that despite its bugs has worked earlier.
- m_col = m_seq == null && model instanceof TemplateCollectionModel
- ? (TemplateCollectionModel) model
- : null;
- if (m_seq == null && m_col == null) {
- throw MessageUtils.newUnexpectedOperandTypeException(
- target, model,
- MessageUtils.SEQUENCE_OR_COLLECTION,
- MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
- null, env);
- }
-
- m_env = env;
+ this.iterable = iterable;
}
@Override
public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException {
- TemplateModel target = args[0];
- Number startIndex = getOptionalNumberArgument(args, 1, this);
+ TemplateModel searched = args[0];
+ Integer startIndex = getOptionalIntArgument(args, 1, this);
int foundAtIdx;
if (startIndex != null) {
- // TODO [FM3] Prefer Col?
- // In 2.3.x only, we prefer TemplateSequenceModel for
- // backward compatibility:
- foundAtIdx = m_seq != null
- ? findInSeq(target, startIndex.intValue())
- : findInCol(target, startIndex.intValue());
+ foundAtIdx = iterable instanceof TemplateSequenceModel
+ ? findInSeq(searched, (TemplateSequenceModel) iterable, startIndex, env)
+ : findInIter(searched, startIndex, env);
} else {
- // TODO [FM3] Prefer Col?
- // In 2.3.x only, we prefer TemplateSequenceModel for
- // backward compatibility:
- foundAtIdx = m_seq != null
- ? findInSeq(target)
- : findInCol(target);
+ foundAtIdx = iterable instanceof TemplateSequenceModel
+ ? findInSeq(searched, (TemplateSequenceModel) iterable, env)
+ : findInIter(searched, env);
}
return foundAtIdx == -1 ? TemplateNumberModel.MINUS_ONE : new SimpleNumber(foundAtIdx);
}
@@ -453,37 +367,41 @@ class BuiltInsForSequences {
return ArgumentArrayLayout.TWO_POSITIONAL_PARAMETERS;
}
- int findInCol(TemplateModel target) throws TemplateException {
- return findInCol(target, 0, Integer.MAX_VALUE);
+ int findInIter(TemplateModel searched, Environment env) throws TemplateException {
+ return findInIter(searched, 0, Integer.MAX_VALUE, env);
}
- int findInCol(TemplateModel target, int startIndex)
+ int findInIter(TemplateModel searched, int startIndex, Environment env)
throws TemplateException {
- if (m_dir == 1) {
- return findInCol(target, startIndex, Integer.MAX_VALUE);
+ if (findFirst) {
+ return findInIter(searched, startIndex, Integer.MAX_VALUE, env);
} else {
- return findInCol(target, 0, startIndex);
+ return findInIter(searched, 0, startIndex, env);
}
}
- int findInCol(TemplateModel target,
- final int allowedRangeStart, final int allowedRangeEnd)
+ int findInIter(TemplateModel searched,
+ final int allowedRangeStart, final int allowedRangeEnd, Environment env)
throws TemplateException {
if (allowedRangeEnd < 0) return -1;
- TemplateModelIterator it = m_col.iterator();
+ TemplateModelIterator it = iterable.iterator();
int foundAtIdx = -1; // -1 is the return value for "not found"
int idx = 0;
searchItem: while (it.hasNext()) {
- if (idx > allowedRangeEnd) break searchItem;
+ if (idx > allowedRangeEnd) {
+ break searchItem;
+ }
TemplateModel current = it.next();
if (idx >= allowedRangeStart) {
- if (modelsEqual(idx, current, target, m_env)) {
+ if (modelsEqual(idx, current, searched, env)) {
foundAtIdx = idx;
- if (m_dir == 1) break searchItem; // "find first"
- // Otherwise it's "find last".
+ // Don't stop if it's "find last".
+ if (findFirst) {
+ break searchItem;
+ }
}
}
idx++;
@@ -491,25 +409,26 @@ class BuiltInsForSequences {
return foundAtIdx;
}
- int findInSeq(TemplateModel target)
+ int findInSeq(TemplateModel searched, TemplateSequenceModel seq, Environment env)
throws TemplateException {
- final int seqSize = m_seq.size();
+ final int seqSize = seq.getCollectionSize();
final int actualStartIndex;
-
- if (m_dir == 1) {
+
+ if (findFirst) {
actualStartIndex = 0;
} else {
actualStartIndex = seqSize - 1;
}
-
- return findInSeq(target, actualStartIndex, seqSize);
+
+ return findInSeq(searched, seq, actualStartIndex, seqSize, env);
}
- private int findInSeq(TemplateModel target, int startIndex)
+ private int findInSeq(
+ TemplateModel searched, TemplateSequenceModel seq, int startIndex, Environment env)
throws TemplateException {
- int seqSize = m_seq.size();
+ int seqSize = seq.getCollectionSize();
- if (m_dir == 1) {
+ if (findFirst) {
if (startIndex >= seqSize) {
return -1;
}
@@ -525,19 +444,19 @@ class BuiltInsForSequences {
}
}
- return findInSeq(target, startIndex, seqSize);
+ return findInSeq(searched, seq, startIndex, seqSize, env);
}
private int findInSeq(
- TemplateModel target, int scanStartIndex, int seqSize)
+ TemplateModel searched, TemplateSequenceModel seq, int scanStartIndex, int seqSize, Environment env)
throws TemplateException {
- if (m_dir == 1) {
+ if (findFirst) {
for (int i = scanStartIndex; i < seqSize; i++) {
- if (modelsEqual(i, m_seq.get(i), target, m_env)) return i;
+ if (modelsEqual(i, seq.get(i), searched, env)) return i;
}
} else {
for (int i = scanStartIndex; i >= 0; i--) {
- if (modelsEqual(i, m_seq.get(i), target, m_env)) return i;
+ if (modelsEqual(i, seq.get(i), searched, env)) return i;
}
}
return -1;
@@ -545,16 +464,15 @@ class BuiltInsForSequences {
}
- private int m_dir;
+ private boolean findFirst;
- seq_index_ofBI(int dir) {
- m_dir = dir;
+ seq_index_ofBI(boolean findFirst) {
+ this.findFirst = findFirst;
}
@Override
- TemplateModel _eval(Environment env)
- throws TemplateException {
- return new BIMethod(env);
+ TemplateModel calculateResult(TemplateIterableModel model) throws TemplateException {
+ return new BIMethod(model);
}
}
@@ -567,7 +485,8 @@ class BuiltInsForSequences {
}
@Override
- public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
+ public TemplateModel execute(
+ TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException {
String[] subvars;
TemplateModel obj = args[0];
@@ -575,10 +494,11 @@ class BuiltInsForSequences {
subvars = new String[] { ((TemplateStringModel) obj).getAsString() };
} else if (obj instanceof TemplateSequenceModel) {
TemplateSequenceModel seq = (TemplateSequenceModel) obj;
- int ln = seq.size();
+ int ln = seq.getCollectionSize();
subvars = new String[ln];
+ TemplateModelIterator iter = seq.iterator();
for (int i = 0; i < ln; i++) {
- TemplateModel item = seq.get(i);
+ TemplateModel item = iter.next();
if (!(item instanceof TemplateStringModel)) {
throw new TemplateException(
"The argument to ?", key, "(key), when it's a sequence, must be a "
@@ -711,7 +631,7 @@ class BuiltInsForSequences {
*/
static TemplateSequenceModel sort(TemplateSequenceModel seq, String[] keyNames)
throws TemplateException {
- int ln = seq.size();
+ int ln = seq.getCollectionSize();
if (ln == 0) return seq;
ArrayList res = new ArrayList(ln);
@@ -721,8 +641,9 @@ class BuiltInsForSequences {
// Copy the Seq into a Java List[KVP] (also detects key type at the 1st item):
int keyType = KEY_TYPE_NOT_YET_DETECTED;
Comparator keyComparator = null;
+ TemplateModelIterator iter = seq.iterator();
for (int i = 0; i < ln; i++) {
- final TemplateModel item = seq.get(i);
+ final TemplateModel item = iter.next();
TemplateModel key = item;
for (int keyNameI = 0; keyNameI < keyNamesLn; keyNameI++) {
try {
@@ -757,8 +678,7 @@ class BuiltInsForSequences {
} else if (key instanceof TemplateNumberModel) {
keyType = KEY_TYPE_NUMBER;
keyComparator = new NumericalKVPComparator(
- Environment.getCurrentEnvironment()
- .getArithmeticEngine());
+ Environment.getCurrentEnvironment().getArithmeticEngine());
} else if (key instanceof TemplateDateModel) {
keyType = KEY_TYPE_DATE;
keyComparator = new DateKVPComparator();
@@ -877,8 +797,7 @@ class BuiltInsForSequences {
}
private static boolean modelsEqual(
- int seqItemIndex, TemplateModel seqItem, TemplateModel searchedItem,
- Environment env)
+ int seqItemIndex, TemplateModel seqItem, TemplateModel searchedItem, Environment env)
throws TemplateException {
try {
return _EvalUtils.compare(
@@ -894,7 +813,7 @@ class BuiltInsForSequences {
" to the searched item:\n", new _DelayedGetMessage(ex));
}
}
-
+
// Can't be instantiated
private BuiltInsForSequences() { }
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
index bbdb18f..80429b8 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
@@ -95,7 +95,7 @@ class BuiltInsForStringsBasic {
@Override
TemplateModel _eval(Environment env) throws TemplateException {
return new BIMethod(target.evalAndCoerceToStringOrUnsupportedMarkup(env,
- "For sequences/collections (lists and such) use \"?seqContains\" instead."));
+ "For iterables (like sequences) use \"?seqContains\" instead."));
}
}
@@ -252,7 +252,7 @@ class BuiltInsForStringsBasic {
@Override
TemplateModel _eval(Environment env) throws TemplateException {
return new BIMethod(target.evalAndCoerceToStringOrUnsupportedMarkup(env,
- "For sequences/collections (lists and such) use \"?seqIndexOf\" instead."));
+ "For iterables (like seqiences) use \"?seqIndexOf\" instead."));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java
index d1c42cc..26821a3 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java
@@ -151,7 +151,7 @@ class BuiltInsForStringsMisc {
if (model instanceof TemplateSequenceModel) {
sourceExpr = ((ASTExpression) new ASTExpDynamicKeyName(target, new ASTExpNumberLiteral(0))
.copyLocationFrom(target));
- if (((TemplateSequenceModel) model).size() > 1) {
+ if (((TemplateSequenceModel) model).getCollectionSize() > 1) {
id = ((ASTExpression) new ASTExpDynamicKeyName(target, new ASTExpNumberLiteral(1))
.copyLocationFrom(target)).evalAndCoerceToPlainText(env);
}
@@ -168,7 +168,6 @@ class BuiltInsForStringsMisc {
final Template interpretedTemplate;
try {
- ParsingConfiguration pCfg = parentTemplate.getParsingConfiguration();
// pCfg.outputFormat+autoEscapingPolicy is exceptional: it's inherited from the lexical context
interpretedTemplate = new Template(
(parentTemplate.getLookupName() != null ? parentTemplate.getLookupName() : "nameless_template") + "->" + id,
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
index cb09e95..679b641 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
@@ -27,12 +27,12 @@ import java.util.regex.Pattern;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.TemplateStringModel;
+import org.apache.freemarker.core.model.impl.SequenceTemplateModelIterator;
import org.apache.freemarker.core.model.impl.SimpleString;
import org.apache.freemarker.core.util._StringUtils;
@@ -152,8 +152,7 @@ class BuiltInsForStringsRegexp {
// Represents the match
- static class RegexMatchModel
- implements TemplateBooleanModel, TemplateCollectionModel, TemplateSequenceModel {
+ static class RegexMatchModel implements TemplateBooleanModel, TemplateSequenceModel {
static class MatchWithGroups implements TemplateStringModel {
final String matchedInputPart;
final String[] groups;
@@ -172,15 +171,14 @@ class BuiltInsForStringsRegexp {
return matchedInputPart;
}
}
+
final Pattern pattern;
-
final String input;
+
private Matcher firedEntireInputMatcher;
private Boolean entireInputMatched;
-
private TemplateSequenceModel entireInputMatchGroups;
-
- private ArrayList matchingInputParts;
+ private ArrayList<TemplateModel> matchingInputParts;
RegexMatchModel(Pattern pattern, String input) {
this.pattern = pattern;
@@ -189,17 +187,34 @@ class BuiltInsForStringsRegexp {
@Override
public TemplateModel get(int i) throws TemplateException {
- ArrayList matchingInputParts = this.matchingInputParts;
+ if (i < 0) {
+ return null;
+ }
+ ArrayList<TemplateModel> matchingInputParts = this.matchingInputParts;
if (matchingInputParts == null) {
matchingInputParts = getMatchingInputPartsAndStoreResults();
}
- return (TemplateModel) matchingInputParts.get(i);
+ return i < matchingInputParts.size() ? matchingInputParts.get(i) : null;
}
-
+
+ @Override
+ public int getCollectionSize() throws TemplateException {
+ ArrayList<TemplateModel> matchingInputParts = this.matchingInputParts;
+ if (matchingInputParts == null) {
+ matchingInputParts = getMatchingInputPartsAndStoreResults();
+ }
+ return matchingInputParts.size();
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return getCollectionSize() == 0;
+ }
+
@Override
public boolean getAsBoolean() {
Boolean result = entireInputMatched;
- return result != null ? result.booleanValue() : isEntrieInputMatchesAndStoreResults();
+ return result != null ? result : isEntireInputMatchesAndStoreResults();
}
TemplateModel getGroups() {
@@ -207,7 +222,7 @@ class BuiltInsForStringsRegexp {
if (entireInputMatchGroups == null) {
Matcher t = firedEntireInputMatcher;
if (t == null) {
- isEntrieInputMatchesAndStoreResults();
+ isEntireInputMatchesAndStoreResults();
t = firedEntireInputMatcher;
}
final Matcher firedEntireInputMatcher = t;
@@ -217,8 +232,7 @@ class BuiltInsForStringsRegexp {
@Override
public TemplateModel get(int i) throws TemplateException {
try {
- // Avoid IndexOutOfBoundsException:
- if (i > firedEntireInputMatcher.groupCount()) {
+ if (i < 0 || i > firedEntireInputMatcher.groupCount()) {
return null;
}
@@ -229,22 +243,27 @@ class BuiltInsForStringsRegexp {
}
@Override
- public int size() throws TemplateException {
- try {
- return firedEntireInputMatcher.groupCount() + 1;
- } catch (Exception e) {
- throw new TemplateException("Failed to get regular expression match group count", e);
- }
+ public int getCollectionSize() throws TemplateException {
+ return firedEntireInputMatcher.groupCount() + 1;
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return getCollectionSize() == 0;
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new SequenceTemplateModelIterator(this);
}
-
};
this.entireInputMatchGroups = entireInputMatchGroups;
}
return entireInputMatchGroups;
}
- private ArrayList getMatchingInputPartsAndStoreResults() throws TemplateException {
- ArrayList matchingInputParts = new ArrayList();
+ private ArrayList<TemplateModel> getMatchingInputPartsAndStoreResults() throws TemplateException {
+ ArrayList<TemplateModel> matchingInputParts = new ArrayList<>();
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
@@ -255,17 +274,17 @@ class BuiltInsForStringsRegexp {
return matchingInputParts;
}
- private boolean isEntrieInputMatchesAndStoreResults() {
+ private boolean isEntireInputMatchesAndStoreResults() {
Matcher matcher = pattern.matcher(input);
boolean matches = matcher.matches();
firedEntireInputMatcher = matcher;
- entireInputMatched = Boolean.valueOf(matches);
+ entireInputMatched = matches;
return matches;
}
@Override
public TemplateModelIterator iterator() {
- final ArrayList matchingInputParts = this.matchingInputParts;
+ final ArrayList<TemplateModel> matchingInputParts = this.matchingInputParts;
if (matchingInputParts == null) {
final Matcher matcher = pattern.matcher(input);
return new TemplateModelIterator() {
@@ -275,7 +294,7 @@ class BuiltInsForStringsRegexp {
@Override
public boolean hasNext() {
- final ArrayList matchingInputParts = RegexMatchModel.this.matchingInputParts;
+ final ArrayList<TemplateModel> matchingInputParts = RegexMatchModel.this.matchingInputParts;
if (matchingInputParts == null) {
return hasFindInfo;
} else {
@@ -285,7 +304,7 @@ class BuiltInsForStringsRegexp {
@Override
public TemplateModel next() throws TemplateException {
- final ArrayList matchingInputParts = RegexMatchModel.this.matchingInputParts;
+ final ArrayList<TemplateModel> matchingInputParts = RegexMatchModel.this.matchingInputParts;
if (matchingInputParts == null) {
if (!hasFindInfo) {
throw new TemplateException("There were no more regular expression matches");
@@ -295,11 +314,7 @@ class BuiltInsForStringsRegexp {
hasFindInfo = matcher.find();
return result;
} else {
- try {
- return (TemplateModel) matchingInputParts.get(nextIdx++);
- } catch (IndexOutOfBoundsException e) {
- throw new TemplateException("There were no more regular expression matches", e);
- }
+ return matchingInputParts.get(nextIdx++);
}
}
@@ -316,24 +331,12 @@ class BuiltInsForStringsRegexp {
@Override
public TemplateModel next() throws TemplateException {
- try {
- return (TemplateModel) matchingInputParts.get(nextIdx++);
- } catch (IndexOutOfBoundsException e) {
- throw new TemplateException("There were no more regular expression matches", e);
- }
+ return matchingInputParts.get(nextIdx++);
}
};
}
}
- @Override
- public int size() throws TemplateException {
- ArrayList matchingInputParts = this.matchingInputParts;
- if (matchingInputParts == null) {
- matchingInputParts = getMatchingInputPartsAndStoreResults();
- }
- return matchingInputParts.size();
- }
}
// Can't be instantiated
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
index c0af937..26d5a0e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
@@ -48,7 +48,7 @@ import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.TemplateCallableModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateDateModel;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateFunctionModel;
@@ -669,8 +669,11 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
}
TemplateSequenceModel children = node.getChildNodes();
- if (children == null) return;
- for (int i = 0; i < children.size(); i++) {
+ if (children == null) {
+ return;
+ }
+ int size = children.getCollectionSize();
+ for (int i = 0; i < size; i++) {
TemplateNodeModel child = (TemplateNodeModel) children.get(i);
if (child != null) {
invokeNodeHandlerFor(child, namespaces);
@@ -2195,7 +2198,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
final TemplateHashModel result = new TemplateHashModel() {
@Override
- public boolean isEmpty() {
+ public boolean isEmptyHash() {
return false;
}
@@ -2213,8 +2216,8 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
return new TemplateHashModelEx() {
@Override
- public boolean isEmpty() throws TemplateException {
- return result.isEmpty();
+ public boolean isEmptyHash() throws TemplateException {
+ return result.isEmptyHash();
}
@Override
@@ -2226,18 +2229,18 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
// configuration shared variables even though
// the hash will return them, if only for BWC reasons
@Override
- public TemplateCollectionModel values() throws TemplateException {
+ public TemplateIterableModel values() throws TemplateException {
return ((TemplateHashModelEx) rootDataModel).values();
}
@Override
- public TemplateCollectionModel keys() throws TemplateException {
+ public TemplateIterableModel keys() throws TemplateException {
return ((TemplateHashModelEx) rootDataModel).keys();
}
@Override
- public int size() throws TemplateException {
- return ((TemplateHashModelEx) rootDataModel).size();
+ public int getHashSize() throws TemplateException {
+ return ((TemplateHashModelEx) rootDataModel).getHashSize();
}
};
}
@@ -2253,7 +2256,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
return new TemplateHashModel() {
@Override
- public boolean isEmpty() {
+ public boolean isEmptyHash() {
return false;
}
@@ -2333,7 +2336,8 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
throws TemplateException {
TemplateDirectiveModel result = null;
int i;
- for (i = startIndex; i < nodeNamespaces.size(); i++) {
+ int size = nodeNamespaces.getCollectionSize();
+ for (i = startIndex; i < size; i++) {
Namespace ns = null;
try {
ns = (Namespace) nodeNamespaces.get(i);
@@ -2850,25 +2854,25 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
@Override
- public int size() {
+ public int getHashSize() {
ensureInitializedRTE();
- return super.size();
+ return super.getHashSize();
}
@Override
- public boolean isEmpty() {
+ public boolean isEmptyHash() {
ensureInitializedRTE();
- return super.isEmpty();
+ return super.isEmptyHash();
}
@Override
- public TemplateCollectionModel keys() {
+ public TemplateIterableModel keys() {
ensureInitializedRTE();
return super.keys();
}
@Override
- public TemplateCollectionModel values() {
+ public TemplateIterableModel values() {
ensureInitializedRTE();
return super.values();
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/InvalidReferenceException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/InvalidReferenceException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/InvalidReferenceException.java
index 20d2c10..2cd4fd1 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/InvalidReferenceException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/InvalidReferenceException.java
@@ -65,7 +65,7 @@ public class InvalidReferenceException extends TemplateException {
private static final String TIP_JSP_TAGLIBS =
"The \"JspTaglibs\" variable isn't a core FreeMarker feature; "
+ "it's only available when templates are invoked through org.apache.freemarker.servlet.FreemarkerServlet"
- + " (or other custom FreeMarker-JSP integration solution).";
+ + " (or through some other custom FreeMarker-JSP integration solution).";
/**
* Creates and invalid reference exception that contains no information about what was missing or null.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/ListableRightUnboundedRangeModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ListableRightUnboundedRangeModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ListableRightUnboundedRangeModel.java
deleted file mode 100644
index 0b7e94e..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ListableRightUnboundedRangeModel.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core;
-
-import java.math.BigInteger;
-
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.impl.SimpleNumber;
-
-/**
- * This is the model used for right-unbounded ranges since Incompatible Improvements 2.3.21.
- */
-final class ListableRightUnboundedRangeModel extends RightUnboundedRangeModel implements TemplateCollectionModel {
-
- ListableRightUnboundedRangeModel(int begin) {
- super(begin);
- }
-
- @Override
- public int size() throws TemplateException {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public TemplateModelIterator iterator() throws TemplateException {
- return new TemplateModelIterator() {
- boolean needInc;
- int nextType = 1;
- int nextInt = getBegining();
- long nextLong;
- BigInteger nextBigInteger;
-
- @Override
- public TemplateModel next() throws TemplateException {
- if (needInc) {
- switch (nextType) {
- case 1:
- if (nextInt < Integer.MAX_VALUE) {
- nextInt++;
- } else {
- nextType = 2;
- nextLong = nextInt + 1L;
- }
- break;
-
- case 2:
- if (nextLong < Long.MAX_VALUE) {
- nextLong++;
- } else {
- nextType = 3;
- nextBigInteger = BigInteger.valueOf(nextLong);
- nextBigInteger = nextBigInteger.add(BigInteger.ONE);
- }
- break;
-
- default: // 3
- nextBigInteger = nextBigInteger.add(BigInteger.ONE);
- }
- }
- needInc = true;
- return nextType == 1 ? new SimpleNumber(nextInt)
- : (nextType == 2 ? new SimpleNumber(nextLong)
- : new SimpleNumber(nextBigInteger));
- }
-
- @Override
- public boolean hasNext() throws TemplateException {
- return true;
- }
-
- };
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
index b8354d7..7b9952e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
@@ -20,13 +20,11 @@
package org.apache.freemarker.core;
import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateDateModel;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateStringModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._StringUtils;
@@ -80,13 +78,11 @@ class MessageUtils {
EXPECTED_TYPES_STRING_COERCABLE_TYPES_AND_TOM[i] = TemplateMarkupOutputModel.class;
}
- static final String SEQUENCE_OR_COLLECTION = "sequence or collection";
- static final Class[] EXPECTED_TYPES_SEQUENCE_OR_COLLECTION = new Class[] {
- TemplateSequenceModel.class, TemplateCollectionModel.class
- };
+ static final String EXPECTED_TYPE_ITERABLE_DESC = "iterable (like a sequence)";
- // Can't be instantiated
- private MessageUtils() { }
+ private MessageUtils() {
+ // Not meant to be instantiated
+ }
static String formatLocationForSimpleParsingError(String templateSourceOrLookupName, int line, int column) {
return formatLocation("in", templateSourceOrLookupName, line, column);
@@ -271,6 +267,15 @@ class MessageUtils {
}
static TemplateException newUnexpectedOperandTypeException(
+ ASTExpression blamed, TemplateModel model, String expectedTypesDesc, Class<? extends TemplateModel> expectedType,
+ Object[] tips,
+ Environment env)
+ throws InvalidReferenceException {
+ return newUnexpectedOperandTypeException(
+ blamed, model, expectedTypesDesc, new Class[] { expectedType }, tips, env);
+ }
+
+ static TemplateException newUnexpectedOperandTypeException(
ASTExpression blamed, TemplateModel model, String expectedTypesDesc, Class[] expectedTypes, Object[] tips,
Environment env)
throws InvalidReferenceException {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollection.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollection.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollection.java
new file mode 100644
index 0000000..da90371
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollection.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.util.Collection;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+
+/**
+ * A collection where each items is already a {@link TemplateModel}, so no {@link ObjectWrapper} need to be specified.
+ */
+class NativeCollection implements TemplateCollectionModel {
+
+ private final Collection<TemplateModel> collection;
+
+ public NativeCollection(Collection<TemplateModel> collection) {
+ this.collection = collection;
+ }
+
+ @Override
+ public int getCollectionSize() {
+ return collection.size();
+ }
+
+ @Override
+ public boolean isEmptyCollection() {
+ return collection.isEmpty();
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new NativeTemplateModelIterator(collection.iterator());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollectionEx.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollectionEx.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollectionEx.java
deleted file mode 100644
index 119cae5..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeCollectionEx.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-
-/**
- * A collection where each items is already a {@link TemplateModel}, so no {@link ObjectWrapper} need to be specified.
- */
-class NativeCollectionEx implements TemplateCollectionModelEx {
-
- private final Collection<TemplateModel> collection;
-
- public NativeCollectionEx(Collection<TemplateModel> collection) {
- this.collection = collection;
- }
-
- @Override
- public int size() {
- return collection.size();
- }
-
- @Override
- public boolean isEmpty() {
- return collection.isEmpty();
- }
-
- @Override
- public TemplateModelIterator iterator() throws TemplateException {
- return new TemplateModelIterator() {
-
- private final Iterator<TemplateModel> iterator = collection.iterator();
-
- @Override
- public TemplateModel next() throws TemplateException {
- if (!iterator.hasNext()) {
- throw new TemplateException("The collection has no more items.");
- }
-
- return iterator.next();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeHashEx2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeHashEx2.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeHashEx2.java
index a7b2415..bb505c6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeHashEx2.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeHashEx2.java
@@ -25,7 +25,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -45,7 +45,7 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
}
@Override
- public int size() throws TemplateException {
+ public int getHashSize() throws TemplateException {
return map.size();
}
@@ -55,7 +55,7 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
}
@Override
- public boolean isEmpty() throws TemplateException {
+ public boolean isEmptyHash() throws TemplateException {
return map.isEmpty();
}
@@ -89,13 +89,13 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
}
@Override
- public TemplateCollectionModel keys() throws TemplateException {
- return new NativeStringCollectionCollectionEx(map.keySet());
+ public TemplateIterableModel keys() throws TemplateException {
+ return new NativeStringCollectionCollection(map.keySet());
}
@Override
- public TemplateCollectionModel values() throws TemplateException {
- return new NativeCollectionEx(map.values());
+ public TemplateIterableModel values() throws TemplateException {
+ return new NativeCollection(map.values());
}
public TemplateModel put(String key, TemplateModel value) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
index 5a43ef6..b5febb8 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
@@ -25,6 +25,7 @@ import java.util.Collection;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateSequenceModel;
/**
@@ -49,25 +50,53 @@ class NativeSequence implements TemplateSequenceModel, Serializable {
this.items.addAll(items);
}
- public void add(TemplateModel tm) {
+ void add(TemplateModel tm) {
items.add(tm);
}
- public void addAll(Collection<TemplateModel> items) {
+ void addAll(Collection<TemplateModel> items) {
this.items.addAll(items);
}
- public void clear() {
+ void clear() {
items.clear();
}
@Override
public TemplateModel get(int index) throws TemplateException {
- return items.get(index);
+ return index < items.size() && index >= 0 ? items.get(index) : null;
}
@Override
- public int size() throws TemplateException {
+ public int getCollectionSize() throws TemplateException {
return items.size();
}
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return items.isEmpty();
+ }
+
+ /**
+ * Do not call when you will still add items to the sequence!
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ private int nextIndex = 0;
+ private final int size = items.size();
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return items.get(nextIndex++);
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return nextIndex < size;
+ }
+ };
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringArraySequence.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringArraySequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringArraySequence.java
index a74a63e..5aaf62b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringArraySequence.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringArraySequence.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.core;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.impl.DefaultArrayAdapter;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -41,12 +42,34 @@ class NativeStringArraySequence implements TemplateSequenceModel {
@Override
public TemplateModel get(int index) throws TemplateException {
- return index < items.length ? new SimpleString(items[index]) : null;
+ return index < items.length && index >= 0 ? new SimpleString(items[index]) : null;
}
@Override
- public int size() throws TemplateException {
+ public int getCollectionSize() throws TemplateException {
return items.length;
}
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return items.length == 0;
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ private int nextIndex;
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return new SimpleString(items[nextIndex++]);
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return nextIndex < items.length;
+ }
+ };
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollection.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollection.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollection.java
new file mode 100644
index 0000000..7793789
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollection.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
+import org.apache.freemarker.core.model.impl.SimpleString;
+
+/**
+ * Adapts (not copies) a {@link Collection} of {@link String}-s with on-the-fly wrapping of the items to {@link
+ * SimpleString}-s. The important difference to {@link DefaultNonListCollectionAdapter} is that it doesn't depend on an
+ * {@link ObjectWrapper}, which is needed to guarantee the behavior of some template language constructs. The important
+ * difference to {@link NativeCollection} is that it doesn't need upfront conversion to {@link TemplateModel}-s
+ * (performance).
+ */
+class NativeStringCollectionCollection implements TemplateCollectionModel {
+
+ private final Collection<String> collection;
+
+ public NativeStringCollectionCollection(Collection<String> collection) {
+ this.collection = collection;
+ }
+
+ @Override
+ public int getCollectionSize() {
+ return collection.size();
+ }
+
+ @Override
+ public boolean isEmptyCollection() {
+ return collection.isEmpty();
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+
+ private final Iterator<String> iterator = collection.iterator();
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return new SimpleString(iterator.next());
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollectionEx.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollectionEx.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollectionEx.java
deleted file mode 100644
index 78b2099..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringCollectionCollectionEx.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core;
-
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
-import org.apache.freemarker.core.model.impl.SimpleString;
-
-/**
- * Adapts (not copies) a {@link Collection} of {@link String}-s with on-the-fly wrapping of the items to {@link
- * SimpleString}-s. The important difference to {@link DefaultNonListCollectionAdapter} is that it doesn't depend on an
- * {@link ObjectWrapper}, which is needed to guarantee the behavior of some template language constructs. The important
- * difference to {@link NativeCollectionEx} is that it doesn't need upfront conversion to {@link TemplateModel}-s
- * (performance).
- */
-class NativeStringCollectionCollectionEx implements TemplateCollectionModelEx {
-
- private final Collection<String> collection;
-
- public NativeStringCollectionCollectionEx(Collection<String> collection) {
- this.collection = collection;
- }
-
- @Override
- public int size() {
- return collection.size();
- }
-
- @Override
- public boolean isEmpty() {
- return collection.isEmpty();
- }
-
- @Override
- public TemplateModelIterator iterator() throws TemplateException {
- return new TemplateModelIterator() {
-
- private final Iterator<String> iterator = collection.iterator();
-
- @Override
- public TemplateModel next() throws TemplateException {
- if (!iterator.hasNext()) {
- throw new TemplateException("The collection has no more items.");
- }
-
- return new SimpleString(iterator.next());
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
- };
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringListSequence.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringListSequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringListSequence.java
index 8ab167e..4ddfe0d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringListSequence.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeStringListSequence.java
@@ -23,6 +23,7 @@ import java.util.List;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.impl.DefaultListAdapter;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -44,12 +45,34 @@ class NativeStringListSequence implements TemplateSequenceModel {
@Override
public TemplateModel get(int index) throws TemplateException {
- return index < items.size() ? new SimpleString(items.get(index)) : null;
+ return index < items.size() && index >= 0 ? new SimpleString(items.get(index)) : null;
}
@Override
- public int size() throws TemplateException {
+ public int getCollectionSize() throws TemplateException {
return items.size();
}
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return items.isEmpty();
+ }
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ private int nextIndex;
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return new SimpleString(items.get(nextIndex++));
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return nextIndex < items.size();
+ }
+ };
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/NativeTemplateModelIterator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeTemplateModelIterator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeTemplateModelIterator.java
new file mode 100644
index 0000000..c1c51a3
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeTemplateModelIterator.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.util.Iterator;
+
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+
+class NativeTemplateModelIterator implements TemplateModelIterator {
+
+ private final Iterator<TemplateModel> iterator;
+
+ NativeTemplateModelIterator(Iterator<TemplateModel> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return iterator.next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/RangeModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/RangeModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/RangeModel.java
index 512102a..00be690 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/RangeModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/RangeModel.java
@@ -31,19 +31,20 @@ abstract class RangeModel implements TemplateSequenceModel, java.io.Serializable
this.begin = begin;
}
- final int getBegining() {
+ final int getBeginning() {
return begin;
}
@Override
- final public TemplateModel get(int index) throws TemplateException {
- if (index < 0 || index >= size()) {
- throw new TemplateException("Range item index ", Integer.valueOf(index), " is out of bounds.");
- }
- long value = begin + getStep() * (long) index;
+ public final TemplateModel get(int index) throws TemplateException {
+ return index < getCollectionSize() && index >= 0 ? uncheckedGet(index) : null;
+ }
+
+ protected final TemplateModel uncheckedGet(long index) {
+ long value = begin + getStep() * index;
return value <= Integer.MAX_VALUE ? new SimpleNumber((int) value) : new SimpleNumber(value);
}
-
+
/**
* @return {@code 1} or {@code -1}; other return values need not be properly handled until FTL supports other steps.
*/
@@ -52,7 +53,5 @@ abstract class RangeModel implements TemplateSequenceModel, java.io.Serializable
abstract boolean isRightUnbounded();
abstract boolean isRightAdaptive();
-
- abstract boolean isAffactedByStringSlicingBug();
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/RightUnboundedRangeModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/RightUnboundedRangeModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/RightUnboundedRangeModel.java
index e135d18..04ab6bc 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/RightUnboundedRangeModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/RightUnboundedRangeModel.java
@@ -19,8 +19,18 @@
package org.apache.freemarker.core;
-abstract class RightUnboundedRangeModel extends RangeModel {
-
+import java.math.BigInteger;
+
+import org.apache.freemarker.core.model.TemplateIterableModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+
+/**
+ * This is the model used for right-unbounded ranges
+ */
+final class RightUnboundedRangeModel extends RangeModel implements TemplateIterableModel {
+
RightUnboundedRangeModel(int begin) {
super(begin);
}
@@ -34,15 +44,71 @@ abstract class RightUnboundedRangeModel extends RangeModel {
final boolean isRightUnbounded() {
return true;
}
-
+
@Override
final boolean isRightAdaptive() {
return true;
}
@Override
- final boolean isAffactedByStringSlicingBug() {
+ public int getCollectionSize() throws TemplateException {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
return false;
}
+
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ boolean needInc;
+ int nextType = 1;
+ int nextInt = getBeginning();
+ long nextLong;
+ BigInteger nextBigInteger;
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ if (needInc) {
+ switch (nextType) {
+ case 1:
+ if (nextInt < Integer.MAX_VALUE) {
+ nextInt++;
+ } else {
+ nextType = 2;
+ nextLong = nextInt + 1L;
+ }
+ break;
+
+ case 2:
+ if (nextLong < Long.MAX_VALUE) {
+ nextLong++;
+ } else {
+ nextType = 3;
+ nextBigInteger = BigInteger.valueOf(nextLong);
+ nextBigInteger = nextBigInteger.add(BigInteger.ONE);
+ }
+ break;
+
+ default: // 3
+ nextBigInteger = nextBigInteger.add(BigInteger.ONE);
+ }
+ }
+ needInc = true;
+ return nextType == 1 ? new SimpleNumber(nextInt)
+ : (nextType == 2 ? new SimpleNumber(nextLong)
+ : new SimpleNumber(nextBigInteger));
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return true;
+ }
+
+ };
+
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
index a8e2ed1..30b869c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
@@ -26,13 +26,12 @@ import java.util.Date;
import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine;
import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateStringModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util._ClassUtils;
@@ -338,7 +337,7 @@ public class _EvalUtils {
* {@link TemplateValueFormat} involved produces.
*
* @param seqTip
- * Tip to display if the value type is not coercable, but it's sequence or collection.
+ * Tip to display if the value type is not coercable, but it's iterable.
*
* @return Never {@code null}
*/
@@ -384,7 +383,7 @@ public class _EvalUtils {
* 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.
+ * Tip to display if the value type is not coercable, but it's iterable.
*
* @return Never {@code null}
*/
@@ -417,7 +416,7 @@ public class _EvalUtils {
* markup. This should be used rarely, where the user clearly intend to use the plain text variant of the format.
*
* @param seqTip
- * Tip to display if the value type is not coercable, but it's sequence or collection.
+ * Tip to display if the value type is not coercable, but it's iterable.
*
* @return Never {@code null}
*/
@@ -469,7 +468,7 @@ public class _EvalUtils {
exp, tm,
supportsTOM ? STRING_COERCABLE_TYPES_OR_TOM_DESC : STRING_COERCABLE_TYPES_DESC,
supportsTOM ? EXPECTED_TYPES_STRING_COERCABLE_TYPES_AND_TOM : EXPECTED_TYPES_STRING_COERCABLE,
- seqHint != null && (tm instanceof TemplateSequenceModel || tm instanceof TemplateCollectionModel)
+ seqHint != null && tm instanceof TemplateIterableModel
? new Object[] { seqHint }
: null,
env);