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/10/19 23:23:30 UTC
incubator-freemarker git commit: Moved the keyValuePairIterator()
method from TemplateHashModelEx2 to TemplateHashModelEx. (Now
TemplateHashModelEx2 is unnecessary, but I haven't removed it yet.)
Repository: incubator-freemarker
Updated Branches:
refs/heads/3 22ecffb4b -> 884d22afd
Moved the keyValuePairIterator() method from TemplateHashModelEx2 to TemplateHashModelEx. (Now TemplateHashModelEx2 is unnecessary, but I haven't removed it yet.)
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/884d22af
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/884d22af
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/884d22af
Branch: refs/heads/3
Commit: 884d22afd8525a2df731c94e1fbc0bfb3000b63a
Parents: 22ecffb
Author: ddekany <dd...@apache.org>
Authored: Fri Oct 20 01:23:14 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Fri Oct 20 01:23:14 2017 +0200
----------------------------------------------------------------------
FM3-CHANGE-LOG.txt | 4 +
.../impl/Java8DefaultObjectWrapperTest.java | 8 +-
.../freemarker/core/ConcatenatedHashTest.java | 217 +++++++++++++++++++
.../freemarker/core/ListBreakContinueTest.java | 6 +
.../model/impl/DefaultObjectWrapperTest.java | 8 +-
.../templatesuite/models/AllTemplateModels.java | 5 +
.../models/HashAndStringModel.java | 5 +
.../core/templatesuite/models/Listables.java | 7 +
.../core/userpkg/TestTemplateCallableModel.java | 5 +-
.../org/apache/freemarker/core/ASTDirList.java | 10 +-
.../freemarker/core/ASTExpAddOrConcat.java | 169 +++++++++++----
.../apache/freemarker/core/ASTExpDefault.java | 5 +-
.../freemarker/core/ASTExpHashLiteral.java | 9 +-
.../org/apache/freemarker/core/Environment.java | 7 +-
.../apache/freemarker/core/NativeHashEx2.java | 9 +-
.../core/debug/RmiDebuggedEnvironmentImpl.java | 29 +++
.../freemarker/core/model/EmptyHashModel.java | 2 +-
.../core/model/EmptyKeyValuePairIterator.java | 4 +-
.../core/model/GeneralPurposeNothing.java | 2 +-
.../core/model/TemplateHashModelEx.java | 48 ++++
.../core/model/TemplateHashModelEx2.java | 50 +----
.../freemarker/core/model/impl/BeanModel.java | 40 +++-
.../core/model/impl/ClassIntrospector.java | 3 +-
.../core/model/impl/DefaultMapAdapter.java | 2 +-
.../model/impl/MapKeyValuePairIterator.java | 10 +-
.../freemarker/core/model/impl/SimpleHash.java | 2 +-
.../freemarker/core/model/impl/StaticModel.java | 5 +
.../apache/freemarker/core/util/DeepUnwrap.java | 4 +-
.../servlet/HttpRequestHashModel.java | 28 +++
.../servlet/HttpRequestParametersHashModel.java | 32 +++
.../freemarker/servlet/jsp/JspTagModelBase.java | 5 +-
.../freemarker/spring/model/UrlFunction.java | 7 +-
32 files changed, 606 insertions(+), 141 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index 0480d51..8564541 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -434,6 +434,10 @@ Core / Models and Object wrapping
- `TemplateHashModelEx.keys()` and `values()` returns `TemplateCollectoinModel`, just as in FM2, but in FM3
`TemplateCollectoinModel` has `getCollectionSize()` and `isEmptyCollection` method. So this affects
`TemplateHashModelEx` implementations as well.
+ - Map-like interfaces:
+ - [TODO: in progress] `TemplateHashModelEx2` was removed, as the `keyValuePairIterator()` method was moved to `TemplateHashModelEx`,
+ so now the two interfaces would be the same.
+- BeanModel.keys() and values() are now final methods. Override BeanModel.keySet() and/or get(String) instead.
Core / Template loading and caching
...................................
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
index 2afe94c..fdeac75 100644
--- a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
@@ -23,20 +23,20 @@ import static org.junit.Assert.*;
import org.apache.freemarker.core.Configuration;
import org.apache.freemarker.core.NonTemplateCallPlace;
import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateStringModel;
-import org.apache.freemarker.core.util.CallableUtils;
import org.apache.freemarker.core.model.TemplateHashModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.TemplateStringModel;
+import org.apache.freemarker.core.util.CallableUtils;
import org.junit.Test;
public class Java8DefaultObjectWrapperTest {
+
+ private static final DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
@Test
public void testDefaultMethodRecognized() throws TemplateException {
- DefaultObjectWrapper.Builder owb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
- DefaultObjectWrapper ow = owb.build();
TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
{
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConcatenatedHashTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConcatenatedHashTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConcatenatedHashTest.java
new file mode 100644
index 0000000..70c5c07
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConcatenatedHashTest.java
@@ -0,0 +1,217 @@
+package org.apache.freemarker.core;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.ObjectWrappingException;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePair;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePairIterator;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class ConcatenatedHashTest {
+
+ private static final ImmutableMap<String, Integer> ABCD_MAP = ImmutableMap.of("a", 1, "b", 2, "c", 3, "d", 4);
+ private static final ImmutableMap<String, Integer> CD_MAP = ImmutableMap.of("c", 3, "d", 4);
+ private static final ImmutableMap<String, Integer> AB_MAP = ImmutableMap.of("a", 1, "b", 2);
+ private static final ImmutableMap<String, Integer> ABC33_MAP = ImmutableMap.of("a", 1, "b", 2, "c", 33);
+ private static final ImmutableMap<String, Integer> C33DAB_MAP = ImmutableMap.of("c", 33, "d", 4, "a", 1, "b", 2);
+
+ private static final Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+ private static final ObjectWrapperAndUnwrapper ow = (ObjectWrapperAndUnwrapper) cfg.getObjectWrapper();
+
+ @Test
+ public void testHashPlusHash() throws Exception {
+ TemplateHashModel r = getConcatenatedModel(toHashModelNonEx(AB_MAP), toHashModelNonEx(CD_MAP));
+ assertThat(r, not(instanceOf(TemplateHashModelEx.class)));
+ assertHashModelContent(ABCD_MAP,
+ r);
+ assertHashModelContent(ABCD_MAP,
+ getConcatenatedModel(toHashModelNonEx(ABC33_MAP), toHashModelNonEx(CD_MAP)));
+ assertHashModelContent(C33DAB_MAP,
+ getConcatenatedModel(toHashModelNonEx(CD_MAP), toHashModelNonEx(ABC33_MAP)));
+ assertHashModelContent(AB_MAP,
+ getConcatenatedModel(
+ toHashModelNonEx(AB_MAP), toHashModelNonEx(Collections.<String, Object>emptyMap())));
+ assertHashModelContent(AB_MAP,
+ getConcatenatedModel(
+ toHashModelNonEx(Collections.<String, Object>emptyMap()), toHashModelNonEx(AB_MAP)));
+ assertHashModelContent(Collections.<String, Object>emptyMap(),
+ getConcatenatedModel(
+ toHashModelNonEx(Collections.<String, Object>emptyMap()),
+ toHashModelNonEx(Collections.<String, Object>emptyMap())));
+ }
+
+ @Test
+ public void testHashExPlusHashEx() throws Exception {
+ TemplateHashModel r = getConcatenatedModel(toHashModelEx(AB_MAP), toHashModelEx(CD_MAP));
+ assertThat(r, instanceOf(TemplateHashModelEx.class));
+ assertHashModelContent(ABCD_MAP,
+ r);
+ assertHashModelContent(ABCD_MAP,
+ getConcatenatedModel(toHashModelEx(ABC33_MAP), toHashModelEx(CD_MAP)));
+ assertHashModelContent(C33DAB_MAP,
+ getConcatenatedModel(toHashModelEx(CD_MAP), toHashModelEx(ABC33_MAP)));
+ assertHashModelContent(AB_MAP,
+ getConcatenatedModel(
+ toHashModelEx(AB_MAP), toHashModelEx(Collections.<String, Object>emptyMap())));
+ assertHashModelContent(AB_MAP,
+ getConcatenatedModel(
+ toHashModelEx(Collections.<String, Object>emptyMap()), toHashModelEx(AB_MAP)));
+ assertHashModelContent(Collections.<String, Object>emptyMap(),
+ getConcatenatedModel(
+ toHashModelEx(Collections.<String, Object>emptyMap()),
+ toHashModelEx(Collections.<String, Object>emptyMap())));
+ }
+
+ @Test
+ public void testNonStringKeyHashExPlusHashEx() throws Exception {
+ TemplateHashModelEx r = (TemplateHashModelEx) getConcatenatedModel(
+ toHashModelEx(ImmutableMap.of(1, "one", 2, "two", Locale.GERMAN, "de", Locale.FRANCE, "fr")),
+ toHashModelEx(ImmutableMap.of(2, "two v2", 3, "three", Locale.FRANCE, "fr v2")));
+ assertEquals(ImmutableList.of(1, 2, Locale.GERMAN, Locale.FRANCE, 3), unwrappedKeysToList(r));
+ assertEquals(ImmutableList.of("one", "two v2", "de", "fr v2", "three"), unwrappedValuesToList(r));
+ }
+
+ private TemplateHashModel getConcatenatedModel(TemplateHashModel h1, TemplateHashModel h2)
+ throws IOException, TemplateException {
+ StringWriter sw = new StringWriter();
+ Environment env = new Template(null, "<#assign r = h1 + h2>", cfg)
+ .createProcessingEnvironment(ImmutableMap.of("h1", h1, "h2", h2), sw);
+ env.process();
+ return (TemplateHashModel) env.getVariable("r");
+ }
+
+ private TemplateHashModelEx toHashModelEx(Map<?, ?> map) throws ObjectWrappingException {
+ TemplateModel tm = cfg.getObjectWrapper().wrap(map);
+ assertThat(tm, instanceOf(TemplateHashModelEx.class));
+ return (TemplateHashModelEx) tm;
+ }
+
+ private TemplateHashModel toHashModelNonEx(Map<String, ?> map) throws ObjectWrappingException {
+ final TemplateHashModelEx tm = toHashModelEx(map);
+ return new TemplateHashModel() {
+
+ @Override
+ public boolean isEmptyHash() throws TemplateException {
+ return tm.isEmptyHash();
+ }
+
+ @Override
+ public TemplateModel get(String key) throws TemplateException {
+ return tm.get(key);
+ }
+ };
+ }
+
+ private void assertHashModelContent(Map<String, ?> expected, TemplateHashModel actual) throws TemplateException {
+ for (Entry<String, ?> ent : expected.entrySet()) {
+ TemplateModel value = actual.get(ent.getKey());
+ assertNotNull(value);
+ assertEquals(ent.getValue(), ow.unwrap(value));
+ }
+
+ assertEquals(expected.isEmpty(), actual.isEmptyHash());
+
+ if (actual instanceof TemplateHashModelEx) {
+ TemplateHashModelEx actualEx = (TemplateHashModelEx) actual;
+
+ assertEquals(expected.size(), actualEx.getHashSize());
+
+ // Keys:
+ {
+ ArrayList<String> expectedKeys = new ArrayList<>(expected.keySet());
+
+ ArrayList<?> actualKeys = unwrappedKeysToList(actualEx);
+ assertEquals(expectedKeys, actualKeys);
+
+ // Without hasNext:
+ ArrayList<String> actualKeys2 = new ArrayList<>();
+ TemplateModelIterator iter = actualEx.keys().iterator();
+ for (int i = 0; i < actualEx.getHashSize(); i++) {
+ actualKeys2.add((String) ow.unwrap(iter.next()));
+ }
+ assertEquals(actualKeys, actualKeys2);
+
+ assertEquals(expectedKeys.size(), actualEx.keys().getCollectionSize());
+ assertEquals(expectedKeys.isEmpty(), actualEx.keys().isEmptyCollection());
+ }
+
+ // Values:
+ {
+ ArrayList<?> expectedValues = new ArrayList<>(expected.values());
+
+ ArrayList<Object> actualValues = unwrappedValuesToList(actualEx);
+ assertEquals(expectedValues, actualValues);
+
+ // Without hasNext:
+ ArrayList<Object> actualValues2 = new ArrayList<>();
+ TemplateModelIterator iter = actualEx.values().iterator();
+ for (int i = 0; i < actualEx.getHashSize(); i++) {
+ actualValues2.add(ow.unwrap(iter.next()));
+ }
+ assertEquals(actualValues, actualValues2);
+
+ assertEquals(expectedValues.size(), actualEx.values().getCollectionSize());
+ assertEquals(expectedValues.isEmpty(), actualEx.values().isEmptyCollection());
+ }
+
+ // Key-value pairs:
+ {
+ ArrayList<Pair<String, ?>> expectedPairs = new ArrayList<>();
+ for (Map.Entry<String, ?> ent : expected.entrySet()) {
+ expectedPairs.add(Pair.of(ent.getKey(), ent.getValue()));
+ }
+
+ ArrayList<Pair<String, ?>> actualPairs = new ArrayList<>();
+ for (KeyValuePairIterator iter = actualEx.keyValuePairIterator(); iter.hasNext();) {
+ KeyValuePair kvp = iter.next();
+ actualPairs.add(Pair.of((String) ow.unwrap(kvp.getKey()), ow.unwrap(kvp.getValue())));
+ }
+ assertEquals(expectedPairs, actualPairs);
+
+ // Without hasNext:
+ ArrayList<Pair<String, ?>> actualPairs2 = new ArrayList<>();
+ KeyValuePairIterator iter = actualEx.keyValuePairIterator();
+ for (int i = 0; i < actualEx.getHashSize(); i++) {
+ KeyValuePair kvp = iter.next();
+ actualPairs2.add(Pair.of((String) ow.unwrap(kvp.getKey()), ow.unwrap(kvp.getValue())));
+ }
+ assertEquals(actualPairs, actualPairs2);
+ }
+ }
+ }
+
+ private ArrayList<?> unwrappedKeysToList(TemplateHashModelEx actualEx) throws TemplateException {
+ ArrayList<Object> actualKeys = new ArrayList<>();
+ for (TemplateModelIterator iter = actualEx.keys().iterator(); iter.hasNext();) {
+ actualKeys.add(ow.unwrap(iter.next()));
+ }
+ return actualKeys;
+ }
+
+ private ArrayList<Object> unwrappedValuesToList(TemplateHashModelEx actualEx) throws TemplateException {
+ ArrayList<Object> actualValues = new ArrayList<>();
+ for (TemplateModelIterator iter = actualEx.values().iterator(); iter.hasNext();) {
+ actualValues.add(ow.unwrap(iter.next()));
+ }
+ return actualValues;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListBreakContinueTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListBreakContinueTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListBreakContinueTest.java
index 86f52f8..f7ef9b7 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListBreakContinueTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListBreakContinueTest.java
@@ -42,6 +42,7 @@ public class ListBreakContinueTest extends TemplateTest {
}
/** Hides the Ex2 features of another hash */
+ // TODO [FM3][CF] Remove
static class NonEx2Hash implements TemplateHashModelEx {
private final TemplateHashModelEx delegate;
@@ -73,6 +74,11 @@ public class ListBreakContinueTest extends TemplateTest {
public TemplateCollectionModel values() throws TemplateException {
return delegate.values();
}
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return delegate.keyValuePairIterator();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
index ba71c6e..00b569f 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
@@ -51,16 +51,16 @@ import org.apache.freemarker.core.model.AdapterTemplateModel;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.ObjectWrappingException;
import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateHashModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
+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.TemplateModelWithAPISupport;
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.TemplateStringModel;
import org.apache.freemarker.core.model.WrapperTemplateModel;
import org.apache.freemarker.core.model.WrappingTemplateModel;
import org.apache.freemarker.core.util.CallableUtils;
@@ -341,7 +341,7 @@ public class DefaultObjectWrapperTest {
assertEquals("c", ((TemplateStringModel) seq.get(2)).getAsString());
assertNull(seq.get(3));
- assertCollectionTMEquals((TemplateIterableModel) seq, 1, null, "c");
+ assertCollectionTMEquals(seq, 1, null, "c");
TemplateModelIterator it = ((TemplateIterableModel) seq).iterator();
it.next();
@@ -900,5 +900,5 @@ public class DefaultObjectWrapperTest {
}
}
-
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/AllTemplateModels.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/AllTemplateModels.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/AllTemplateModels.java
index a5b387c..9fc5a8b 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/AllTemplateModels.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/AllTemplateModels.java
@@ -89,6 +89,11 @@ public class AllTemplateModels implements
}
@Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return KeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
+ }
+
+ @Override
public boolean getAsBoolean() throws TemplateException {
return true;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/HashAndStringModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/HashAndStringModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/HashAndStringModel.java
index 9586b30..3c0fe45 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/HashAndStringModel.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/HashAndStringModel.java
@@ -60,4 +60,9 @@ public class HashAndStringModel implements TemplateHashModelEx, TemplateStringMo
return TemplateCollectionModel.EMPTY_COLLECTION;
}
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return KeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/Listables.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/Listables.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/Listables.java
index 6f83960..f5b9516 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/Listables.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/Listables.java
@@ -39,6 +39,7 @@ import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.WrappingTemplateModel;
import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.MapKeyValuePairIterator;
import org.apache.freemarker.core.model.impl.SimpleCollection;
import org.apache.freemarker.core.model.impl.SimpleHash;
@@ -147,6 +148,7 @@ public class Listables {
new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
}
+ // TODO [FM3][CF] Remove
public static class NonEx2MapAdapter extends WrappingTemplateModel implements TemplateHashModelEx {
private final Map<?, ?> map;
@@ -180,6 +182,11 @@ public class Listables {
public TemplateCollectionModel values() {
return new SimpleCollection(map.values(), getObjectWrapper());
}
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new MapKeyValuePairIterator(map, getObjectWrapper());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
index 879c7d8..21c6ed5 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
@@ -24,6 +24,7 @@ import java.io.Writer;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.TemplateCallableModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateStringModel;
@@ -76,10 +77,10 @@ public abstract class TestTemplateCallableModel implements TemplateCallableModel
}
sb.append(']');
} else if (value instanceof TemplateHashModelEx2) {
- TemplateHashModelEx2.KeyValuePairIterator it = ((TemplateHashModelEx2) value).keyValuePairIterator();
+ TemplateHashModelEx.KeyValuePairIterator it = ((TemplateHashModelEx2) value).keyValuePairIterator();
sb.append('{');
while (it.hasNext()) {
- TemplateHashModelEx2.KeyValuePair kvp = it.next();
+ TemplateHashModelEx.KeyValuePair kvp = it.next();
printValue(kvp.getKey(), sb);
sb.append(": ");
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
index 0262ded..7e4e86c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
@@ -26,9 +26,9 @@ import java.util.Collections;
import org.apache.freemarker.core.model.TemplateBooleanModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePair;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePair;
-import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateIterableModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
@@ -309,14 +309,14 @@ final class ASTDirList extends ASTDirective {
if (listedValue instanceof TemplateHashModelEx) {
TemplateHashModelEx listedHash = (TemplateHashModelEx) listedValue;
if (listedHash instanceof TemplateHashModelEx2) {
- KeyValuePairIterator kvpIter
+ TemplateHashModelEx.KeyValuePairIterator kvpIter
= openedIterator == null ? ((TemplateHashModelEx2) listedHash).keyValuePairIterator()
- : (KeyValuePairIterator) openedIterator;
+ : (TemplateHashModelEx.KeyValuePairIterator) openedIterator;
hashNotEmpty = kvpIter.hasNext();
if (hashNotEmpty) {
if (nestedContentParam1Name != null) {
listLoop: do {
- KeyValuePair kvp = kvpIter.next();
+ TemplateHashModelEx.KeyValuePair kvp = kvpIter.next();
nestedContentParam = kvp.getKey();
nestedContentParam2 = kvp.getValue();
hasNext = kvpIter.hasNext();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
index 230d1a9..320c427 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
@@ -19,13 +19,16 @@
package org.apache.freemarker.core;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
+import org.apache.freemarker.core.model.AdapterTemplateModel;
+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.TemplateHashModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
@@ -34,6 +37,7 @@ import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.TemplateStringModel;
+import org.apache.freemarker.core.model.WrapperTemplateModel;
import org.apache.freemarker.core.model.impl.SimpleNumber;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -123,9 +127,9 @@ final class ASTExpAddOrConcat extends ASTExpression {
if (leftModel instanceof TemplateHashModelEx && rightModel instanceof TemplateHashModelEx) {
TemplateHashModelEx leftModelEx = (TemplateHashModelEx) leftModel;
TemplateHashModelEx rightModelEx = (TemplateHashModelEx) rightModel;
- if (leftModelEx.getHashSize() == 0) {
+ if (leftModelEx.isEmptyHash()) {
return rightModelEx;
- } else if (rightModelEx.getHashSize() == 0) {
+ } else if (rightModelEx.isEmptyHash()) {
return leftModelEx;
} else {
return new ConcatenatedHashEx(leftModelEx, rightModelEx);
@@ -270,8 +274,8 @@ final class ASTExpAddOrConcat extends ASTExpression {
}
private static final class ConcatenatedHashEx extends ConcatenatedHash implements TemplateHashModelEx {
- private TemplateCollectionModel keys;
- private TemplateCollectionModel values;
+ /** Lazily calculated list of key-value pairs; there's only one item per duplicate key. */
+ private Collection<KeyValuePair> kvps;
ConcatenatedHashEx(TemplateHashModelEx left, TemplateHashModelEx right) {
super(left, right);
@@ -279,55 +283,140 @@ final class ASTExpAddOrConcat extends ASTExpression {
@Override
public int getHashSize() throws TemplateException {
- initKeys();
- return keys.getCollectionSize();
+ initKvps();
+ return kvps.size();
}
@Override
public TemplateCollectionModel keys() throws TemplateException {
- initKeys();
- return keys;
+ initKvps();
+ return new TemplateCollectionModel() {
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ private Iterator<KeyValuePair> iter = kvps.iterator();
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return iter.hasNext();
+ }
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return iter.next().getKey();
+ }
+ };
+ }
+
+ @Override
+ public int getCollectionSize() throws TemplateException {
+ return kvps.size();
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return kvps.isEmpty();
+ }
+ };
}
@Override
public TemplateCollectionModel values() throws TemplateException {
- initValues();
- return values;
+ initKvps();
+ return new TemplateCollectionModel() {
+ @Override
+ public TemplateModelIterator iterator() throws TemplateException {
+ return new TemplateModelIterator() {
+ private Iterator<KeyValuePair> iter = kvps.iterator();
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return iter.hasNext();
+ }
+
+ @Override
+ public TemplateModel next() throws TemplateException {
+ return iter.next().getValue();
+ }
+ };
+ }
+
+ @Override
+ public boolean isEmptyCollection() throws TemplateException {
+ return kvps.isEmpty();
+ }
+
+ @Override
+ public int getCollectionSize() throws TemplateException {
+ return kvps.size();
+ }
+ };
+ }
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ initKvps();
+ return new KeyValuePairIterator() {
+ private Iterator<KeyValuePair> iter = kvps.iterator();
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return iter.hasNext();
+ }
+
+ @Override
+ public KeyValuePair next() throws TemplateException {
+ return iter.next();
+ }
+ };
}
- private void initKeys() throws TemplateException {
- if (keys == null) {
- HashSet keySet = new HashSet();
- ArrayList<TemplateModel> keyList = new ArrayList<>();
- addKeys(keySet, keyList, (TemplateHashModelEx) left);
- addKeys(keySet, keyList, (TemplateHashModelEx) right);
- keys = new NativeCollection(keyList);
+ /**
+ * We must precreate the whole key-value pair list, as we have to deal with duplicate keys.
+ */
+ private void initKvps() throws TemplateException {
+ if (kvps != null) {
+ return;
}
+
+ Map<Object, KeyValuePair> kvpsMap = new LinkedHashMap<>();
+ putKVPs(kvpsMap, (TemplateHashModelEx) left);
+ putKVPs(kvpsMap, (TemplateHashModelEx) right);
+ this.kvps = kvpsMap.values();
}
- private static void addKeys(Set keySet, List<TemplateModel> keyList, TemplateHashModelEx hash)
- throws TemplateException {
- for (TemplateModelIterator it = hash.keys().iterator(); it.hasNext(); ) {
- TemplateStringModel tsm = (TemplateStringModel) it.next();
- if (keySet.add(tsm.getAsString())) {
- // The first occurrence of the key decides the index;
- // this is consistent with stuff like java.util.LinkedHashSet.
- keyList.add(tsm);
- }
+ private static void putKVPs(Map<Object, KeyValuePair> kvps, TemplateHashModelEx hash) throws TemplateException {
+ for (KeyValuePairIterator iter = hash.keyValuePairIterator(); iter.hasNext(); ) {
+ KeyValuePair kvp = iter.next();
+ kvps.put(unwrapKey(kvp.getKey()), kvp);
}
- }
+ }
- private void initValues() throws TemplateException {
- if (values == null) {
- ArrayList<TemplateModel> valueList = new ArrayList<>(getHashSize());
- // Note: getHashSize() invokes initKeys()
-
- for (TemplateModelIterator iter = keys.iterator(); iter.hasNext(); ) {
- valueList.add(get(((TemplateStringModel) iter.next()).getAsString()));
- }
- values = new NativeCollection(valueList);
+ private static Object unwrapKey(TemplateModel model) throws TemplateException {
+ if (model instanceof AdapterTemplateModel) {
+ return ((AdapterTemplateModel) model).getAdaptedObject(Object.class);
}
+ if (model instanceof WrapperTemplateModel) {
+ return ((WrapperTemplateModel) model).getWrappedObject();
+ }
+ if (model instanceof TemplateStringModel) {
+ return ((TemplateStringModel) model).getAsString();
+ }
+ if (model instanceof TemplateNumberModel) {
+ return ((TemplateNumberModel) model).getAsNumber();
+ }
+ if (model instanceof TemplateDateModel) {
+ return ((TemplateDateModel) model).getAsDate();
+ }
+ if (model instanceof TemplateBooleanModel) {
+ return Boolean.valueOf(((TemplateBooleanModel) model).getAsBoolean());
+ }
+ // TODO [FM3] Handle List-s, etc.? But wait until FM3 TM-s settle; we might will have TM.getWrappedObject().
+ return new TemplateException(
+ "Can't unwrapp hash key of this type, yet (TODO): ",
+ new _DelayedTemplateLanguageTypeDescription(model));
}
+
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
index 6b6d409..1a54521 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.core;
import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
@@ -83,8 +84,8 @@ class ASTExpDefault extends ASTExpression {
}
@Override
- public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
- return KeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return TemplateHashModelEx.KeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
index 7198f6a..c062c18 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
@@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
import java.util.ListIterator;
import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
@@ -158,8 +159,8 @@ final class ASTExpHashLiteral extends ASTExpression {
}
@Override
- public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
- return new KeyValuePairIterator() {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new TemplateHashModelEx.KeyValuePairIterator() {
private final TemplateModelIterator keyIterator = keys().iterator();
private final TemplateModelIterator valueIterator = values().iterator();
@@ -169,8 +170,8 @@ final class ASTExpHashLiteral extends ASTExpression {
}
@Override
- public KeyValuePair next() throws TemplateException {
- return new KeyValuePair() {
+ public TemplateHashModelEx.KeyValuePair next() throws TemplateException {
+ return new TemplateHashModelEx.KeyValuePair() {
private final TemplateModel key = keyIterator.next();
private final TemplateModel value = valueIterator.next();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/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 e1f9993..75bada7 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
@@ -2266,6 +2266,11 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
public TemplateCollectionModel keys() throws TemplateException {
return ((TemplateHashModelEx) rootDataModel).keys();
}
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return ((TemplateHashModelEx) rootDataModel).keyValuePairIterator();
+ }
@Override
public int getHashSize() throws TemplateException {
@@ -2907,7 +2912,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
@Override
- public KeyValuePairIterator keyValuePairIterator() {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() {
ensureInitializedRTE();
return super.keyValuePairIterator();
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/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 9b39e82..0074171 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
@@ -26,6 +26,7 @@ import java.util.Map;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -60,8 +61,8 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
}
@Override
- public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
- return new KeyValuePairIterator() {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new TemplateHashModelEx.KeyValuePairIterator() {
private final Iterator<Map.Entry<String, TemplateModel>> entrySetIterator = map.entrySet().iterator();
@Override
@@ -70,8 +71,8 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
}
@Override
- public KeyValuePair next() throws TemplateException {
- return new KeyValuePair() {
+ public TemplateHashModelEx.KeyValuePair next() throws TemplateException {
+ return new TemplateHashModelEx.KeyValuePair() {
private final Map.Entry<String, TemplateModel> entry = entrySetIterator.next();
@Override
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java b/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java
index d1c2154..7fad936 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java
@@ -153,6 +153,35 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn
return getHashSize() == 0;
}
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new KeyValuePairIterator() {
+ private final Iterator<String> keyIter = keySet().iterator();
+
+ @Override
+ public KeyValuePair next() throws TemplateException {
+ return new KeyValuePair() {
+ private final String key = keyIter.next();
+
+ @Override
+ public TemplateModel getValue() throws TemplateException {
+ return get(key);
+ }
+
+ @Override
+ public TemplateModel getKey() throws TemplateException {
+ return new SimpleString(key);
+ }
+ };
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return keyIter.hasNext();
+ }
+ };
+ }
+
abstract Collection keySet();
static List composeList(Collection c1, Collection c2) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyHashModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyHashModel.java
index 69ebe26..20aebe2 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyHashModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyHashModel.java
@@ -51,7 +51,7 @@ class EmptyHashModel implements TemplateHashModelEx2, Serializable {
}
@Override
- public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException {
return EmptyKeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyKeyValuePairIterator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyKeyValuePairIterator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyKeyValuePairIterator.java
index 83a0650..9552111 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyKeyValuePairIterator.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyKeyValuePairIterator.java
@@ -23,7 +23,7 @@ import java.util.NoSuchElementException;
import org.apache.freemarker.core.TemplateException;
-class EmptyKeyValuePairIterator implements TemplateHashModelEx2.KeyValuePairIterator {
+class EmptyKeyValuePairIterator implements TemplateHashModelEx.KeyValuePairIterator {
@Override
public boolean hasNext() throws TemplateException {
@@ -31,7 +31,7 @@ class EmptyKeyValuePairIterator implements TemplateHashModelEx2.KeyValuePairIter
}
@Override
- public TemplateHashModelEx2.KeyValuePair next() throws TemplateException {
+ public TemplateHashModelEx.KeyValuePair next() throws TemplateException {
throw new NoSuchElementException("Can't retrieve element from empty key-value pair iterator.");
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/GeneralPurposeNothing.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/GeneralPurposeNothing.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/GeneralPurposeNothing.java
index 438b704..cf3490e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/GeneralPurposeNothing.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/GeneralPurposeNothing.java
@@ -108,7 +108,7 @@ implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, Tem
}
@Override
- public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException {
return EmptyKeyValuePairIterator.EMPTY_KEY_VALUE_PAIR_ITERATOR;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx.java
index 2b5c3a6..30ad102 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx.java
@@ -19,6 +19,8 @@
package org.apache.freemarker.core.model;
+import java.util.Iterator;
+
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.impl.SimpleHash;
@@ -33,6 +35,45 @@ import org.apache.freemarker.core.model.impl.SimpleHash;
public interface TemplateHashModelEx extends TemplateHashModel {
/**
+ * A key-value pair in a hash; used for {@link TemplateHashModelEx.KeyValuePairIterator}.
+ */
+ interface KeyValuePair {
+
+ /**
+ * @return Any type of {@link TemplateModel}, maybe {@code null} (if the hash entry key is {@code null}).
+ */
+ TemplateModel getKey() throws TemplateException;
+
+ /**
+ * @return Any type of {@link TemplateModel}, maybe {@code null} (if the hash entry value is {@code null}).
+ */
+ TemplateModel getValue() throws TemplateException;
+ }
+
+ /**
+ * Iterates over the key-value pairs in a hash. This is very similar to an {@link Iterator}, but has a fixed item
+ * type, can throw {@link TemplateException}-s, and has no {@code remove()} method.
+ */
+ interface KeyValuePairIterator {
+
+ TemplateHashModelEx.KeyValuePairIterator EMPTY_KEY_VALUE_PAIR_ITERATOR = new EmptyKeyValuePairIterator();
+
+ /**
+ * Similar to {@link Iterator#hasNext()}.
+ */
+ boolean hasNext() throws TemplateException;
+
+ /**
+ * Similar to {@link TemplateModelIterator#next()}, but returns a {@link KeyValuePair}-s instead of
+ * {@link TemplateModel}-s. As such, its behavior is undefined too, if it's called when there's no more
+ * items (so you must use {@link #hasNext()}, unless you know how many key-value pairs there are).
+ *
+ * @return Not {@code null}
+ */
+ KeyValuePair next() throws TemplateException;
+ }
+
+ /**
* @return the number of key/value mappings in the hash.
*/
int getHashSize() throws TemplateException;
@@ -48,4 +89,11 @@ public interface TemplateHashModelEx extends TemplateHashModel {
* {@link TemplateModel}-s.
*/
TemplateCollectionModel values() throws TemplateException;
+
+
+ /**
+ * @return The iterator that walks through the key-value pairs in the hash. Not {@code null}.
+ */
+ TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() throws TemplateException;
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx2.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx2.java
index cf8cee4..30a92d4 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx2.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModelEx2.java
@@ -18,61 +18,13 @@
*/
package org.apache.freemarker.core.model;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import org.apache.freemarker.core.TemplateException;
-
/**
* Adds key-value pair listing capability to {@link TemplateHashModelEx}. While in many cases that can also be achieved
* with {@link #keys()} and then {@link #get(String)}, that has some problems. One is that {@link #get(String)} only
* accepts string keys, while {@link #keys()} can return non-string keys too. The other is that calling {@link #keys()}
* and then {@link #get(String)} for each key can be slower than listing the key-value pairs in one go.
*/
+// TODO [FM3][CF] Remove
public interface TemplateHashModelEx2 extends TemplateHashModelEx {
-
- /**
- * @return The iterator that walks through the key-value pairs in the hash. Not {@code null}.
- */
- KeyValuePairIterator keyValuePairIterator() throws TemplateException;
-
- /**
- * A key-value pair in a hash; used for {@link KeyValuePairIterator}.
- */
- interface KeyValuePair {
-
- /**
- * @return Any type of {@link TemplateModel}, maybe {@code null} (if the hash entry key is {@code null}).
- */
- TemplateModel getKey() throws TemplateException;
-
- /**
- * @return Any type of {@link TemplateModel}, maybe {@code null} (if the hash entry value is {@code null}).
- */
- TemplateModel getValue() throws TemplateException;
- }
-
- /**
- * Iterates over the key-value pairs in a hash. This is very similar to an {@link Iterator}, but has a fixed item
- * type, can throw {@link TemplateException}-s, and has no {@code remove()} method.
- */
- interface KeyValuePairIterator {
-
- TemplateHashModelEx2.KeyValuePairIterator EMPTY_KEY_VALUE_PAIR_ITERATOR = new EmptyKeyValuePairIterator();
-
- /**
- * Similar to {@link Iterator#hasNext()}.
- */
- boolean hasNext() throws TemplateException;
-
- /**
- * Similar to {@link Iterator#next()}.
- *
- * @return Not {@code null}
- *
- * @throws NoSuchElementException
- */
- KeyValuePair next() throws TemplateException;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
index 9dbe5b6..b0c99cb 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java
@@ -39,7 +39,6 @@ import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.model.WrapperTemplateModel;
@@ -274,22 +273,48 @@ public class BeanModel
}
@Override
- public TemplateCollectionModel keys() {
+ public final TemplateCollectionModel keys() {
return DefaultNonListCollectionAdapter.adapt(keySet(), wrapper);
}
@Override
- public TemplateCollectionModel values() throws TemplateException {
- List<Object> values = new ArrayList<>(getHashSize());
- TemplateModelIterator it = keys().iterator();
- while (it.hasNext()) {
- String key = ((TemplateStringModel) it.next()).getAsString();
+ public final TemplateCollectionModel values() throws TemplateException {
+ Set<String> keySet = keySet();
+ List<Object> values = new ArrayList<>(keySet().size());
+ for (String key : keySet) {
values.add(get(key));
}
return DefaultNonListCollectionAdapter.adapt(values, wrapper);
}
@Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ final Iterator<String> keyIter = keySet().iterator();
+ return new KeyValuePairIterator() {
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return keyIter.hasNext();
+ }
+
+ @Override
+ public KeyValuePair next() throws TemplateException {
+ final String key = keyIter.next();
+ return new KeyValuePair() {
+ @Override
+ public TemplateModel getValue() throws TemplateException {
+ return get(key);
+ }
+
+ @Override
+ public TemplateModel getKey() throws TemplateException {
+ return new SimpleString(key);
+ }
+ };
+ };
+ };
+ }
+
+ @Override
public String toString() {
return object.toString();
}
@@ -299,6 +324,7 @@ public class BeanModel
* Strings which are available via the TemplateHashModel
* interface. Subclasses that override <tt>invokeGenericGet</tt> to
* provide additional hash keys should also override this method.
+ * Also, if this is overwritten, {@link #getHashSize()} should be too.
*/
protected Set<String> keySet() {
return wrapper.getClassIntrospector().keySet(object.getClass());
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
index 94eca36..c6c9246 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassIntrospector.java
@@ -959,6 +959,7 @@ class ClassIntrospector {
* Returns the number of introspected methods/properties that should be available via the TemplateHashModel
* interface.
*/
+ // TODO [FM3] Too slow. See also keySet().
int keyCount(Class<?> clazz) {
Map<Object, Object> map = get(clazz);
int count = map.size();
@@ -972,7 +973,7 @@ class ClassIntrospector {
* Returns the Set of names of introspected methods/properties that should be available via the TemplateHashModel
* interface.
*/
- // TODO [FM3] Can't we instead return an Iterable<String> that filters out the non-String keys?
+ // TODO [FM3] Far too slow.
@SuppressWarnings("rawtypes")
Set<String> keySet(Class<?> clazz) {
Set<Object> set = new HashSet<>(get(clazz).keySet());
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultMapAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultMapAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultMapAdapter.java
index f24d7c5..9f66026 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultMapAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultMapAdapter.java
@@ -144,7 +144,7 @@ public class DefaultMapAdapter extends WrappingTemplateModel
}
@Override
- public KeyValuePairIterator keyValuePairIterator() {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() {
return new MapKeyValuePairIterator(map, getObjectWrapper());
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/MapKeyValuePairIterator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/MapKeyValuePairIterator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/MapKeyValuePairIterator.java
index 80b6aa5..539267c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/MapKeyValuePairIterator.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/MapKeyValuePairIterator.java
@@ -25,16 +25,16 @@ import java.util.Map.Entry;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ObjectWrapper;
import org.apache.freemarker.core.model.ObjectWrappingException;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePair;
-import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateModel;
/**
* Implementation of {@link KeyValuePairIterator} for a {@link TemplateHashModelEx2} that wraps or otherwise uses a
* {@link Map} internally.
*/
-public class MapKeyValuePairIterator implements KeyValuePairIterator {
+public class MapKeyValuePairIterator implements TemplateHashModelEx.KeyValuePairIterator {
private final Iterator<Entry<?, ?>> entrySetIterator;
@@ -52,9 +52,9 @@ public class MapKeyValuePairIterator implements KeyValuePairIterator {
}
@Override
- public KeyValuePair next() {
+ public TemplateHashModelEx.KeyValuePair next() {
final Entry<?, ?> entry = entrySetIterator.next();
- return new KeyValuePair() {
+ return new TemplateHashModelEx.KeyValuePair() {
@Override
public TemplateModel getKey() throws TemplateException {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java
index 38f2a9b..4ed6a8d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java
@@ -287,7 +287,7 @@ public class SimpleHash extends WrappingTemplateModel implements TemplateHashMod
}
@Override
- public KeyValuePairIterator keyValuePairIterator() {
+ public TemplateHashModelEx.KeyValuePairIterator keyValuePairIterator() {
return new MapKeyValuePairIterator(map, getObjectWrapper());
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
index 684bc63..21c525c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
@@ -102,6 +102,11 @@ final class StaticModel implements TemplateHashModelEx {
public TemplateCollectionModel values() throws TemplateException {
return (TemplateCollectionModel) wrapper.getOuterIdentity().wrap(map.values());
}
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new MapKeyValuePairIterator(map, wrapper.getOuterIdentity());
+ }
private void populate() throws TemplateException {
if (!Modifier.isPublic(clazz.getModifiers())) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-core/src/main/java/org/apache/freemarker/core/util/DeepUnwrap.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/DeepUnwrap.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/DeepUnwrap.java
index eb674cb..500ce65 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/DeepUnwrap.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/DeepUnwrap.java
@@ -40,8 +40,8 @@ import org.apache.freemarker.core.model.WrapperTemplateModel;
/**
* Utility methods for unwrapping {@link TemplateModel}-s.
*/
+// TODO [FM3] Has to be changed or removed. For starters, for Collection-s and Map-s we should use adapters.
public class DeepUnwrap {
- private static final Class OBJECT_CLASS = Object.class;
/**
* Unwraps {@link TemplateModel}-s recursively.
* The converting of the {@link TemplateModel} object happens with the following rules:
@@ -97,7 +97,7 @@ public class DeepUnwrap {
private static Object unwrap(TemplateModel model, TemplateModel nullModel, boolean permissive) throws TemplateException {
if (model instanceof AdapterTemplateModel) {
- return ((AdapterTemplateModel) model).getAdaptedObject(OBJECT_CLASS);
+ return ((AdapterTemplateModel) model).getAdaptedObject(Object.class);
}
if (model instanceof WrapperTemplateModel) {
return ((WrapperTemplateModel) model).getWrappedObject();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestHashModel.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestHashModel.java
index 9a61294..690e3bc 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestHashModel.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestHashModel.java
@@ -32,6 +32,7 @@ import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleCollection;
+import org.apache.freemarker.core.model.impl.SimpleString;
/**
* TemplateHashModel wrapper for a HttpServletRequest attributes.
@@ -93,6 +94,33 @@ public final class HttpRequestHashModel implements TemplateHashModelEx {
}
return new SimpleCollection(values, wrapper);
}
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ final Enumeration<String> namesEnum = request.getAttributeNames();
+ return new KeyValuePairIterator() {
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return namesEnum.hasMoreElements();
+ }
+
+ @Override
+ public KeyValuePair next() throws TemplateException {
+ final String name = namesEnum.nextElement();
+ return new KeyValuePair() {
+ @Override
+ public TemplateModel getValue() throws TemplateException {
+ return wrapper.wrap(request.getAttribute(name));
+ }
+
+ @Override
+ public TemplateModel getKey() throws TemplateException {
+ return new SimpleString(name);
+ }
+ };
+ }
+ };
+ }
public HttpServletRequest getRequest() {
return request;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestParametersHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestParametersHashModel.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestParametersHashModel.java
index 573c4ad..104331a 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestParametersHashModel.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/HttpRequestParametersHashModel.java
@@ -105,6 +105,38 @@ public class HttpRequestParametersHashModel implements TemplateHashModelEx {
}
};
}
+
+
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() throws TemplateException {
+ return new KeyValuePairIterator() {
+ private final List<String> keys = getKeys();
+ private int nextIndex = 0;
+
+ @Override
+ public KeyValuePair next() throws TemplateException {
+ return new KeyValuePair() {
+ private final String key = keys.get(nextIndex++);
+
+ @Override
+ public TemplateModel getValue() throws TemplateException {
+ return objectWrapper.wrap(request.getParameter(key));
+ }
+
+ @Override
+ public TemplateModel getKey() throws TemplateException {
+ return new SimpleString(key);
+ }
+ };
+ }
+
+ @Override
+ public boolean hasNext() throws TemplateException {
+ return nextIndex < keys.size();
+ }
+ };
+ }
private synchronized List<String> getKeys() {
if (keys == null) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
----------------------------------------------------------------------
diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
index 75f1fe2..52e7f9d 100644
--- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
+++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
@@ -39,6 +39,7 @@ import org.apache.freemarker.core._DelayedJQuote;
import org.apache.freemarker.core._DelayedShortClassName;
import org.apache.freemarker.core._ErrorDescriptionBuilder;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModelWithOriginName;
import org.apache.freemarker.core.model.TemplateStringModel;
@@ -74,8 +75,8 @@ abstract class JspTagModelBase implements TemplateModelWithOriginName {
IllegalAccessException {
if (args != null && !args.isEmptyHash()) {
final Object[] argArray = new Object[1];
- for (TemplateHashModelEx2.KeyValuePairIterator iter = args.keyValuePairIterator(); iter.hasNext(); ) {
- final TemplateHashModelEx2.KeyValuePair entry = iter.next();
+ for (TemplateHashModelEx.KeyValuePairIterator iter = args.keyValuePairIterator(); iter.hasNext(); ) {
+ final TemplateHashModelEx.KeyValuePair entry = iter.next();
final Object arg = wrapper.unwrap(entry.getValue());
argArray[0] = arg;
final String paramName = ((TemplateStringModel) entry.getKey()).getAsString();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/884d22af/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
index 71220b1..3381f9c 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
@@ -37,8 +37,9 @@ import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateStringModel;
@@ -114,8 +115,8 @@ class UrlFunction extends AbstractSpringTemplateFunctionModel {
if (!paramsHashModel.isEmptyHash()) {
params = new ArrayList<>();
- for (KeyValuePairIterator pairIt = paramsHashModel.keyValuePairIterator(); pairIt.hasNext();) {
- TemplateHashModelEx2.KeyValuePair pair = pairIt.next();
+ for (TemplateHashModelEx.KeyValuePairIterator pairIt = paramsHashModel.keyValuePairIterator(); pairIt.hasNext();) {
+ TemplateHashModelEx.KeyValuePair pair = pairIt.next();
TemplateModel paramNameModel = pair.getKey();
TemplateModel paramValueModel = pair.getValue();