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/02 08:41:23 UTC

incubator-freemarker git commit: `TemplateHashModelEx.keys()` and `values()` returns `TemplateCollectoinModel`, just as in FM2, but in FM3 `TemplateCollectoinModel` has `getCollectionSize()` and `isEmptyCollection` method. So this affects `TemplateHashMo

Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 6565719b1 -> 99a750b68


`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.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/99a750b6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/99a750b6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/99a750b6

Branch: refs/heads/3
Commit: 99a750b685818becc2b30701766bce30d575ea61
Parents: 6565719
Author: ddekany <dd...@apache.org>
Authored: Sat Sep 2 10:41:09 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sat Sep 2 10:41:09 2017 +0200

----------------------------------------------------------------------
 FM3-CHANGE-LOG.txt                              |  3 +
 .../templatesuite/models/AllTemplateModels.java | 13 +--
 .../models/HashAndStringModel.java              | 10 +--
 .../core/templatesuite/models/Listables.java    | 12 +--
 .../freemarker/core/ASTExpAddOrConcat.java      |  8 +-
 .../apache/freemarker/core/ASTExpDefault.java   | 12 +--
 .../freemarker/core/ASTExpHashLiteral.java      |  8 +-
 .../org/apache/freemarker/core/Environment.java | 12 +--
 .../apache/freemarker/core/NativeHashEx2.java   |  6 +-
 .../core/debug/RmiDebuggedEnvironmentImpl.java  | 12 +--
 .../core/model/EmptyCollectionModel.java        |  4 +
 .../freemarker/core/model/EmptyHashModel.java   |  8 +-
 .../core/model/EmptyIterableModel.java          | 31 +++++++
 .../core/model/GeneralPurposeNothing.java       |  8 +-
 .../core/model/TemplateCollectionModel.java     |  2 +
 .../core/model/TemplateHashModelEx.java         |  4 +-
 .../core/model/TemplateIterableModel.java       |  2 +-
 .../freemarker/core/model/impl/BeanModel.java   |  6 +-
 .../core/model/impl/DefaultMapAdapter.java      | 12 +--
 .../core/model/impl/SimpleCollection.java       | 89 ++++++++++++++++++++
 .../freemarker/core/model/impl/SimpleHash.java  | 11 +--
 .../core/model/impl/SimpleIterable.java         | 15 ++--
 .../freemarker/core/model/impl/StaticModel.java | 10 +--
 .../servlet/HttpRequestHashModel.java           | 12 +--
 .../servlet/HttpRequestParametersHashModel.java | 72 +++++++++-------
 25 files changed, 263 insertions(+), 119 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index dbc017c..5593816 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -223,6 +223,9 @@ Major changes / features
   - `isEmpty` of FM2 `TemplateCollectionModelEx` (now `TemplateCollectionModel`) and FM2 `TemplateHashModel` was renamed
     to `isEmptyCollection` and `isEmptyHash`, so that for multi-typed values can give different results depending on the
     type. Also, for collections `size()` was renamed to `getCollectionSize()`, and for hashes `getHashSize()`.
+  - `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.
 - Removed freemarker.ext.log, our log abstraction layer from the times when there was no clear winner on this field.
   Added org.slf4j:slf4j-api as required dependency instead.
 - Added Spring support to the FreeMarker project (freemarker-spring module), instead of relying Spring developers

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 3a9009b..a5b387c 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
@@ -23,14 +23,15 @@ import java.util.Date;
 
 import org.apache.freemarker.core.TemplateException;
 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.TemplateDateModel;
 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.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.impl.SimpleString;
 
 /**
@@ -78,13 +79,13 @@ public class AllTemplateModels implements
     }
 
     @Override
-    public TemplateIterableModel keys() throws TemplateException {
-        return EMPTY_ITERABLE;
+    public TemplateCollectionModel keys() throws TemplateException {
+        return EMPTY_COLLECTION;
     }
 
     @Override
-    public TemplateIterableModel values() throws TemplateException {
-        return EMPTY_ITERABLE;
+    public TemplateCollectionModel values() throws TemplateException {
+        return EMPTY_COLLECTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 2e0104d..9586b30 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
@@ -20,8 +20,8 @@
 package org.apache.freemarker.core.templatesuite.models;
 
 import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
 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.TemplateStringModel;
 import org.apache.freemarker.core.model.impl.SimpleString;
@@ -51,13 +51,13 @@ public class HashAndStringModel implements TemplateHashModelEx, TemplateStringMo
     }
 
     @Override
-    public TemplateIterableModel keys() throws TemplateException {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel keys() throws TemplateException {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
     @Override
-    public TemplateIterableModel values() throws TemplateException {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel values() throws TemplateException {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 ed8b48d..6f83960 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
@@ -32,14 +32,14 @@ import org.apache.freemarker.core.Configuration;
 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.TemplateIterableModel;
+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.WrappingTemplateModel;
 import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleIterable;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
 import org.apache.freemarker.core.model.impl.SimpleHash;
 
 import com.google.common.collect.ImmutableMap;
@@ -172,13 +172,13 @@ public class Listables {
         }
         
         @Override
-        public TemplateIterableModel keys() {
-            return new SimpleIterable(map.keySet(), getObjectWrapper());
+        public TemplateCollectionModel keys() {
+            return new SimpleCollection(map.keySet(), getObjectWrapper());
         }
         
         @Override
-        public TemplateIterableModel values() {
-            return new SimpleIterable(map.values(), getObjectWrapper());
+        public TemplateCollectionModel values() {
+            return new SimpleCollection(map.values(), getObjectWrapper());
         }
         
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 5fa8eac..b821b44 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
@@ -23,9 +23,9 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
+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.TemplateMarkupOutputModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelIterator;
@@ -284,15 +284,13 @@ final class ASTExpAddOrConcat extends ASTExpression {
         }
 
         @Override
-        public TemplateIterableModel keys()
-        throws TemplateException {
+        public TemplateCollectionModel keys() throws TemplateException {
             initKeys();
             return keys;
         }
 
         @Override
-        public TemplateIterableModel values()
-        throws TemplateException {
+        public TemplateCollectionModel values() throws TemplateException {
             initValues();
             return values;
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 07e12fb..6b6d409 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
@@ -20,8 +20,8 @@
 package org.apache.freemarker.core;
 
 
+import org.apache.freemarker.core.model.TemplateCollectionModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
-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.TemplateSequenceModel;
@@ -73,13 +73,13 @@ class ASTExpDefault extends ASTExpression {
         }
 
         @Override
-        public TemplateIterableModel keys() {
-            return TemplateIterableModel.EMPTY_ITERABLE;
+        public TemplateCollectionModel keys() {
+            return TemplateCollectionModel.EMPTY_COLLECTION;
         }
 
         @Override
-        public TemplateIterableModel values() {
-            return TemplateIterableModel.EMPTY_ITERABLE;
+        public TemplateCollectionModel values() {
+            return TemplateCollectionModel.EMPTY_COLLECTION;
         }
 
         @Override
@@ -88,7 +88,7 @@ class ASTExpDefault extends ASTExpression {
         }
     }
 
-    static final TemplateModel EMPTY_STRING_AND_SEQUENCE_AND_HASH = new EmptyStringAndSequenceAndHash();
+    private static final TemplateModel EMPTY_STRING_AND_SEQUENCE_AND_HASH = new EmptyStringAndSequenceAndHash();
 	
 	private final ASTExpression lho, rho;
 	

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 a6eaab4..dd29369 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
@@ -24,7 +24,7 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.ListIterator;
 
-import org.apache.freemarker.core.model.TemplateIterableModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelIterator;
@@ -108,7 +108,7 @@ final class ASTExpHashLiteral extends ASTExpression {
     private class LinkedHash implements TemplateHashModelEx2 {
 
         private HashMap<String, TemplateModel> map;
-        private TemplateIterableModel keyCollection, valueCollection; // ordered lists of keys and values
+        private TemplateCollectionModel keyCollection, valueCollection; // ordered lists of keys and values
 
         LinkedHash(Environment env) throws TemplateException {
             map = new LinkedHashMap<>();
@@ -128,7 +128,7 @@ final class ASTExpHashLiteral extends ASTExpression {
         }
 
         @Override
-        public TemplateIterableModel keys() {
+        public TemplateCollectionModel keys() {
             if (keyCollection == null) {
                 keyCollection = new IterableAndSequence(new NativeStringCollectionCollection(map.keySet()));
             }
@@ -136,7 +136,7 @@ final class ASTExpHashLiteral extends ASTExpression {
         }
 
         @Override
-        public TemplateIterableModel values() {
+        public TemplateCollectionModel values() {
             if (valueCollection == null) {
                 valueCollection = new IterableAndSequence(new NativeCollection(map.values()));
             }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 26d5a0e..23df374 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.TemplateIterableModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
 import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateDirectiveModel;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
@@ -59,8 +59,8 @@ import org.apache.freemarker.core.model.TemplateModelIterator;
 import org.apache.freemarker.core.model.TemplateModelWithOriginName;
 import org.apache.freemarker.core.model.TemplateNodeModel;
 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.impl.SimpleHash;
 import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
 import org.apache.freemarker.core.templateresolver.TemplateResolver;
@@ -2229,12 +2229,12 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
                 // configuration shared variables even though
                 // the hash will return them, if only for BWC reasons
                 @Override
-                public TemplateIterableModel values() throws TemplateException {
+                public TemplateCollectionModel values() throws TemplateException {
                     return ((TemplateHashModelEx) rootDataModel).values();
                 }
 
                 @Override
-                public TemplateIterableModel keys() throws TemplateException {
+                public TemplateCollectionModel keys() throws TemplateException {
                     return ((TemplateHashModelEx) rootDataModel).keys();
                 }
 
@@ -2866,13 +2866,13 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
         }
 
         @Override
-        public TemplateIterableModel keys() {
+        public TemplateCollectionModel keys() {
             ensureInitializedRTE();
             return super.keys();
         }
 
         @Override
-        public TemplateIterableModel values() {
+        public TemplateCollectionModel values() {
             ensureInitializedRTE();
             return super.values();
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 bb505c6..9b39e82 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.TemplateIterableModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.impl.SimpleString;
@@ -89,12 +89,12 @@ class NativeHashEx2 implements TemplateHashModelEx2, Serializable {
     }
 
     @Override
-    public TemplateIterableModel keys() throws TemplateException {
+    public TemplateCollectionModel keys() throws TemplateException {
         return new NativeStringCollectionCollection(map.keySet());
     }
 
     @Override
-    public TemplateIterableModel values() throws TemplateException {
+    public TemplateCollectionModel values() throws TemplateException {
         return new NativeCollection(map.values());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 4d9ace6..d1c2154 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
@@ -38,11 +38,11 @@ import org.apache.freemarker.core.MutableProcessingConfiguration;
 import org.apache.freemarker.core.ProcessingConfiguration;
 import org.apache.freemarker.core.Template;
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleIterable;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
 import org.apache.freemarker.core.model.impl.SimpleString;
 import org.apache.freemarker.core.util.UndeclaredThrowableException;
 
@@ -133,19 +133,19 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn
         }
 
         @Override
-        public TemplateIterableModel keys() {
-            return new SimpleIterable(keySet(), OBJECT_WRAPPER);
+        public TemplateCollectionModel keys() {
+            return new SimpleCollection(keySet(), OBJECT_WRAPPER);
         }
 
         @Override
-        public TemplateIterableModel values() throws TemplateException {
+        public TemplateCollectionModel values() throws TemplateException {
             Collection keys = keySet();
             List list = new ArrayList(keys.size());
             
             for (Iterator it = keys.iterator(); it.hasNext(); ) {
                 list.add(get((String) it.next()));
             }
-            return new SimpleIterable(list, OBJECT_WRAPPER);
+            return new SimpleCollection(list, OBJECT_WRAPPER);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java
index a38574c..576bd59 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java
@@ -25,6 +25,10 @@ import org.apache.freemarker.core.TemplateException;
 
 class EmptyCollectionModel implements TemplateCollectionModel, Serializable {
 
+    public EmptyCollectionModel() {
+
+    }
+
     @Override
     public int getCollectionSize() throws TemplateException {
         return 0;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 966e0bb..69ebe26 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
@@ -31,13 +31,13 @@ class EmptyHashModel implements TemplateHashModelEx2, Serializable {
     }
 
     @Override
-    public TemplateIterableModel keys() throws TemplateException {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel keys() throws TemplateException {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
     @Override
-    public TemplateIterableModel values() throws TemplateException {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel values() throws TemplateException {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIterableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIterableModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIterableModel.java
new file mode 100644
index 0000000..6200eb9
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIterableModel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.model;
+
+import org.apache.freemarker.core.TemplateException;
+
+class EmptyIterableModel implements TemplateIterableModel {
+
+    @Override
+    public TemplateModelIterator iterator() throws TemplateException {
+        return TemplateModelIterator.EMPTY_ITERATOR;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 3eba7a9..438b704 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
@@ -98,13 +98,13 @@ implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, Tem
     }
 
     @Override
-    public TemplateIterableModel keys() {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel keys() {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
     @Override
-    public TemplateIterableModel values() {
-        return TemplateIterableModel.EMPTY_ITERABLE;
+    public TemplateCollectionModel values() {
+        return TemplateCollectionModel.EMPTY_COLLECTION;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModel.java
index 1562b0a..4dd5624 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModel.java
@@ -27,6 +27,8 @@ import org.apache.freemarker.core.TemplateException;
  */
 public interface TemplateCollectionModel extends TemplateIterableModel {
 
+    TemplateCollectionModel EMPTY_COLLECTION = new EmptyCollectionModel();
+
     /**
      * Returns the number items in this collection, or {@link Integer#MAX_VALUE}, if there are more than
      * {@link Integer#MAX_VALUE} items.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 2a968c9..2b5c3a6 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
@@ -41,11 +41,11 @@ public interface TemplateHashModelEx extends TemplateHashModel {
      * @return a iterable returning the keys in the hash. Every element of the returned by the iterable must implement
      * the {@link TemplateStringModel} (as the keys of hashes are always strings).
      */
-    TemplateIterableModel keys() throws TemplateException;
+    TemplateCollectionModel keys() throws TemplateException;
 
     /**
      * @return An iterable returning the values in the hash. The elements returned by the iterable can be any kind of
      * {@link TemplateModel}-s.
      */
-    TemplateIterableModel values() throws TemplateException;
+    TemplateCollectionModel values() throws TemplateException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java
index 7d67f08..4cd35a2 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java
@@ -39,7 +39,7 @@ import org.apache.freemarker.core.TemplateException;
  */
 public interface TemplateIterableModel extends TemplateModel {
 
-    TemplateCollectionModel EMPTY_ITERABLE = new EmptyCollectionModel();
+    TemplateIterableModel EMPTY_ITERABLE = new EmptyIterableModel();
 
     /**
      * Retrieves an iterator that is used to iterate over the elements of something.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 06dd2c0..3f4c45b 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
@@ -37,7 +37,7 @@ import org.apache.freemarker.core._DelayedJQuote;
 import org.apache.freemarker.core._DelayedTemplateLanguageTypeDescription;
 import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.ObjectWrappingException;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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;
@@ -288,12 +288,12 @@ public class BeanModel
     }
 
     @Override
-    public TemplateIterableModel keys() {
+    public TemplateCollectionModel keys() {
         return new IterableAndSequence(DefaultNonListCollectionAdapter.adapt(keySet(), wrapper));
     }
 
     @Override
-    public TemplateIterableModel values() throws TemplateException {
+    public TemplateCollectionModel values() throws TemplateException {
         List<Object> values = new ArrayList<>(getHashSize());
         TemplateModelIterator it = keys().iterator();
         while (it.hasNext()) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 f663990..f24d7c5 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
@@ -27,7 +27,7 @@ import org.apache.freemarker.core._DelayedJQuote;
 import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.ObjectWrapperWithAPISupport;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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;
@@ -66,7 +66,7 @@ public class DefaultMapAdapter extends WrappingTemplateModel
         return new DefaultMapAdapter(map, wrapper);
     }
     
-    private DefaultMapAdapter(Map map, ObjectWrapper wrapper) {
+    private DefaultMapAdapter(Map map, ObjectWrapperWithAPISupport wrapper) {
         super(wrapper);
         this.map = map;
     }
@@ -134,13 +134,13 @@ public class DefaultMapAdapter extends WrappingTemplateModel
     }
 
     @Override
-    public TemplateIterableModel keys() {
-        return new SimpleIterable(map.keySet(), getObjectWrapper());
+    public TemplateCollectionModel keys() {
+        return DefaultNonListCollectionAdapter.adapt(map.keySet(), (ObjectWrapperWithAPISupport) getObjectWrapper());
     }
 
     @Override
-    public TemplateIterableModel values() {
-        return new SimpleIterable(map.values(), getObjectWrapper());
+    public TemplateCollectionModel values() {
+        return DefaultNonListCollectionAdapter.adapt(map.values(), (ObjectWrapperWithAPISupport) getObjectWrapper());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleCollection.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleCollection.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleCollection.java
new file mode 100644
index 0000000..748a9a2
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleCollection.java
@@ -0,0 +1,89 @@
+/*
+ * 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.model.impl;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.freemarker.core.TemplateException;
+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.WrappingTemplateModel;
+
+/**
+ * A simple implementation of {@link TemplateCollectionModel}.
+ * <p>
+ * This class is thread-safe. The returned {@link TemplateModelIterator}-s are <em>not</em> thread-safe.
+ */
+public class SimpleCollection extends WrappingTemplateModel implements TemplateCollectionModel, Serializable {
+
+    private final Collection<?> collection;
+
+    public SimpleCollection(Collection<?> collection, ObjectWrapper wrapper) {
+        super(wrapper);
+        this.collection = collection;
+    }
+
+    @Override
+    public int getCollectionSize() throws TemplateException {
+        return collection.size();
+    }
+
+    @Override
+    public boolean isEmptyCollection() throws TemplateException {
+        return collection.isEmpty();
+    }
+
+    /**
+     * Retrieves a template model iterator that is used to iterate over the elements in this iterable.
+     */
+    @Override
+    public TemplateModelIterator iterator() {
+        return new SimpleTemplateModelIterator(collection.iterator());
+    }
+    
+    /**
+     * Wraps an {@link Iterator}; not thread-safe.
+     */
+    private class SimpleTemplateModelIterator implements TemplateModelIterator {
+        
+        private final Iterator<?> iterator;
+
+        SimpleTemplateModelIterator(Iterator<?> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        public TemplateModel next() throws TemplateException {
+            Object value  = iterator.next();
+            return value instanceof TemplateModel ? (TemplateModel) value : wrap(value);
+        }
+
+        @Override
+        public boolean hasNext() throws TemplateException {
+            return iterator.hasNext();
+        }
+
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 e2c867e..38f2a9b 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
@@ -30,7 +30,7 @@ import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core._DelayedJQuote;
 import org.apache.freemarker.core.model.ObjectWrapper;
 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.TemplateHashModelEx;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
 import org.apache.freemarker.core.model.TemplateModel;
@@ -277,17 +277,18 @@ public class SimpleHash extends WrappingTemplateModel implements TemplateHashMod
     }
 
     @Override
-    public TemplateIterableModel keys() {
-        return new SimpleIterable(map.keySet(), getObjectWrapper());
+    public TemplateCollectionModel keys() {
+        return new SimpleCollection(map.keySet(), getObjectWrapper());
     }
 
     @Override
-    public TemplateIterableModel values() {
-        return new SimpleIterable(map.values(), getObjectWrapper());
+    public TemplateCollectionModel values() {
+        return new SimpleCollection(map.values(), getObjectWrapper());
     }
 
     @Override
     public KeyValuePairIterator keyValuePairIterator() {
         return new MapKeyValuePairIterator(map, getObjectWrapper());
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleIterable.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleIterable.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleIterable.java
index 1856535..34ce021 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleIterable.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleIterable.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.core.model.impl;
 
 import java.io.Serializable;
 import java.util.Iterator;
+import java.util.List;
 
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.model.ObjectWrapper;
@@ -31,15 +32,15 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
 
 /**
  * A simple implementation of {@link TemplateIterableModel}.
- * It's able to wrap <tt>java.util.Iterator</tt>-s and <tt>java.util.Collection</tt>-s.
- * If you wrap an <tt>Iterator</tt>, the variable can be &lt;#list&gt;-ed only once!
+ * It's able to wrap {@link Iterable}-s and {@link Iterator}-s.
+ * If you wrap an {@link Iterator}, the variable can be &lt;#list&gt;-ed only once!
  *
- * <p>Consider using {@link SimpleSequence} instead of this class if you want to wrap <tt>Iterator</tt>s.
- * <tt>SimpleSequence</tt> will read all elements of the <tt>Iterator</tt>, and store them in a <tt>List</tt>
+ * <p>Consider using {@link SimpleSequence} instead of this class if you want to wrap {@link Iterator}-s.
+ * {@link SimpleSequence} will read all elements of the {@link Iterator}, and store them in a {@link List}
  * (this may cause too high resource consumption in some applications), so you can list the variable
- * for unlimited times. Also, if you want to wrap <tt>Collection</tt>s, and then list the resulting
- * variable for many times, <tt>SimpleSequence</tt> may gives better performance, as the
- * wrapping of non-<tt>TemplateModel</tt> objects happens only once.
+ * for unlimited times. Also, if you want to wrap {@link Iterable}-s, and then list the resulting
+ * variable for many times, {@link SimpleSequence} may gives better performance, as the
+ * wrapping of non-{@link TemplateModel} objects happens only once.
  *
  * <p>This class is thread-safe. The returned {@link TemplateModelIterator}-s
  * are <em>not</em> thread-safe.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 1ea6027..684bc63 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
@@ -27,7 +27,7 @@ import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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;
@@ -94,13 +94,13 @@ final class StaticModel implements TemplateHashModelEx {
     }
     
     @Override
-    public TemplateIterableModel keys() throws TemplateException {
-        return (TemplateIterableModel) wrapper.getOuterIdentity().wrap(map.keySet());
+    public TemplateCollectionModel keys() throws TemplateException {
+        return (TemplateCollectionModel) wrapper.getOuterIdentity().wrap(map.keySet());
     }
     
     @Override
-    public TemplateIterableModel values() throws TemplateException {
-        return (TemplateIterableModel) wrapper.getOuterIdentity().wrap(map.values());
+    public TemplateCollectionModel values() throws TemplateException {
+        return (TemplateCollectionModel) wrapper.getOuterIdentity().wrap(map.values());
     }
 
     private void populate() throws TemplateException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 0a159e9..9a61294 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
@@ -28,10 +28,10 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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.SimpleIterable;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
 
 /**
  * TemplateHashModel wrapper for a HttpServletRequest attributes.
@@ -77,21 +77,21 @@ public final class HttpRequestHashModel implements TemplateHashModelEx {
     }
     
     @Override
-    public TemplateIterableModel keys() {
+    public TemplateCollectionModel keys() {
         ArrayList keys = new ArrayList();
         for (Enumeration enumeration = request.getAttributeNames(); enumeration.hasMoreElements(); ) {
             keys.add(enumeration.nextElement());
         }
-        return new SimpleIterable(keys.iterator(), wrapper);
+        return new SimpleCollection(keys, wrapper);
     }
     
     @Override
-    public TemplateIterableModel values() {
+    public TemplateCollectionModel values() {
         ArrayList values = new ArrayList();
         for (Enumeration enumeration = request.getAttributeNames(); enumeration.hasMoreElements(); ) {
             values.add(request.getAttribute((String) enumeration.nextElement()));
         }
-        return new SimpleIterable(values.iterator(), wrapper);
+        return new SimpleCollection(values, wrapper);
     }
 
     public HttpServletRequest getRequest() {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/99a750b6/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 25833ef..573c4ad 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
@@ -21,16 +21,17 @@ package org.apache.freemarker.servlet;
 
 import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateIterableModel;
+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.SimpleIterable;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
 import org.apache.freemarker.core.model.impl.SimpleString;
 
 /**
@@ -40,7 +41,7 @@ import org.apache.freemarker.core.model.impl.SimpleString;
 public class HttpRequestParametersHashModel implements TemplateHashModelEx {
     private final HttpServletRequest request;
     private final ObjectWrapper objectWrapper;
-    private List keys;
+    private List<String> keys;
         
     public HttpRequestParametersHashModel(HttpServletRequest request, ObjectWrapper objectWrapper) {
         this.request = request;
@@ -64,38 +65,51 @@ public class HttpRequestParametersHashModel implements TemplateHashModelEx {
     }
     
     @Override
-    public TemplateIterableModel keys() {
-        return new SimpleIterable(getKeys().iterator(), objectWrapper);
+    public TemplateCollectionModel keys() {
+        return new SimpleCollection(getKeys(), objectWrapper);
     }
     
     @Override
-    public TemplateIterableModel values() {
-        final Iterator iter = getKeys().iterator();
-        return new SimpleIterable(
-            new Iterator() {
-                @Override
-                public boolean hasNext() {
-                    return iter.hasNext();
-                }
-                @Override
-                public Object next() {
-                    return request.getParameter((String) iter.next());
-                }
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
-                }
-            }, objectWrapper);
-    }
+    public TemplateCollectionModel values() {
+        return new TemplateCollectionModel() {
+            private final List<String> paramNames = getKeys();
+
+            @Override
+            public int getCollectionSize() throws TemplateException {
+                return paramNames.size();
+            }
+
+            @Override
+            public boolean isEmptyCollection() throws TemplateException {
+                return paramNames.isEmpty();
+            }
+
+            @Override
+            public TemplateModelIterator iterator() throws TemplateException {
+                return new TemplateModelIterator() {
+                    int nextIndex;
 
-    protected String transcode(String string) {
-        return string;
+                    @Override
+                    public TemplateModel next() throws TemplateException {
+                        TemplateModel result = objectWrapper.wrap(
+                                request.getParameter(paramNames.get(nextIndex)));
+                        nextIndex++;
+                        return result;
+                    }
+
+                    @Override
+                    public boolean hasNext() throws TemplateException {
+                        return nextIndex < paramNames.size();
+                    }
+                };
+            }
+        };
     }
 
-    private synchronized List getKeys() {
+    private synchronized List<String> getKeys() {
         if (keys == null) {
-            keys = new ArrayList();
-            for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements(); ) {
+            keys = new ArrayList<>();
+            for (Enumeration<String> enumeration = request.getParameterNames(); enumeration.hasMoreElements(); ) {
                 keys.add(enumeration.nextElement());
             }
         }