You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/09/01 18:58:22 UTC

[3/6] incubator-freemarker git commit: Reworked list/iterable-like TemplateModel interfaced. Now we have TemplateIterableModel (which is like TemplateCollectionModel in FM2), TemplateCollectionModel (which similar to TemplateCollectionModelEx in FM2) tha

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebugModelImpl.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebugModelImpl.java b/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebugModelImpl.java
index debe879..5334692 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebugModelImpl.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/debug/RmiDebugModelImpl.java
@@ -27,7 +27,7 @@ import java.util.List;
 
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
 import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateDirectiveModel;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
@@ -84,9 +84,9 @@ class RmiDebugModelImpl extends UnicastRemoteObject implements DebugModel {
     @Override
     public int size() throws TemplateException {
         if (model instanceof TemplateSequenceModel) {
-            return ((TemplateSequenceModel) model).size();
+            return ((TemplateSequenceModel) model).getCollectionSize();
         }
-        return ((TemplateHashModelEx) model).size();
+        return ((TemplateHashModelEx) model).getHashSize();
     }
 
     @Override
@@ -107,7 +107,7 @@ class RmiDebugModelImpl extends UnicastRemoteObject implements DebugModel {
     @Override
     public DebugModel[] getCollection() throws TemplateException, RemoteException {
         List list = new ArrayList();
-        TemplateModelIterator i = ((TemplateCollectionModel) model).iterator();
+        TemplateModelIterator i = ((TemplateIterableModel) model).iterator();
         while (i.hasNext()) {
             list.add(getDebugModel(i.next()));
         }
@@ -152,7 +152,7 @@ class RmiDebugModelImpl extends UnicastRemoteObject implements DebugModel {
         if (model instanceof TemplateDateModel) type += TYPE_DATE;
         if (model instanceof TemplateBooleanModel) type += TYPE_BOOLEAN;
         if (model instanceof TemplateSequenceModel) type += TYPE_SEQUENCE;
-        if (model instanceof TemplateCollectionModel) type += TYPE_COLLECTION;
+        if (model instanceof TemplateIterableModel) type += TYPE_COLLECTION;
         if (model instanceof TemplateHashModelEx) type += TYPE_HASH_EX;
         if (model instanceof TemplateHashModel) type += TYPE_HASH;
         if (model instanceof TemplateFunctionModel) type += TYPE_FUNCTION;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 be2953d..4d9ace6 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.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
 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.SimpleCollection;
+import org.apache.freemarker.core.model.impl.SimpleIterable;
 import org.apache.freemarker.core.model.impl.SimpleString;
 import org.apache.freemarker.core.util.UndeclaredThrowableException;
 
@@ -128,29 +128,29 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn
     
     private abstract static class DebugMapModel implements TemplateHashModelEx {
         @Override
-        public int size() {
+        public int getHashSize() {
             return keySet().size();
         }
 
         @Override
-        public TemplateCollectionModel keys() {
-            return new SimpleCollection(keySet(), OBJECT_WRAPPER);
+        public TemplateIterableModel keys() {
+            return new SimpleIterable(keySet(), OBJECT_WRAPPER);
         }
 
         @Override
-        public TemplateCollectionModel values() throws TemplateException {
+        public TemplateIterableModel 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 SimpleCollection(list, OBJECT_WRAPPER);
+            return new SimpleIterable(list, OBJECT_WRAPPER);
         }
 
         @Override
-        public boolean isEmpty() {
-            return size() == 0;
+        public boolean isEmptyHash() {
+            return getHashSize() == 0;
         }
         
         abstract Collection keySet();

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionExModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionExModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionExModel.java
deleted file mode 100644
index 34f8029..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionExModel.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core.model;
-
-import java.io.Serializable;
-
-import org.apache.freemarker.core.TemplateException;
-
-class EmptyCollectionExModel implements TemplateCollectionModelEx, Serializable {
-
-    @Override
-    public int size() throws TemplateException {
-        return 0;
-    }
-
-    @Override
-    public boolean isEmpty() throws TemplateException {
-        return true;
-    }
-
-    @Override
-    public TemplateModelIterator iterator() throws TemplateException {
-        return TemplateModelIterator.EMPTY_ITERATOR;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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
new file mode 100644
index 0000000..a38574c
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyCollectionModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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 java.io.Serializable;
+
+import org.apache.freemarker.core.TemplateException;
+
+class EmptyCollectionModel implements TemplateCollectionModel, Serializable {
+
+    @Override
+    public int getCollectionSize() throws TemplateException {
+        return 0;
+    }
+
+    @Override
+    public boolean isEmptyCollection() throws TemplateException {
+        return true;
+    }
+
+    @Override
+    public TemplateModelIterator iterator() throws TemplateException {
+        return TemplateModelIterator.EMPTY_ITERATOR;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 0b32160..966e0bb 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
@@ -26,18 +26,18 @@ import org.apache.freemarker.core.TemplateException;
 class EmptyHashModel implements TemplateHashModelEx2, Serializable {
 
     @Override
-    public int size() throws TemplateException {
+    public int getHashSize() throws TemplateException {
         return 0;
     }
 
     @Override
-    public TemplateCollectionModel keys() throws TemplateException {
-        return TemplateCollectionModel.EMPTY_COLLECTION;
+    public TemplateIterableModel keys() throws TemplateException {
+        return TemplateIterableModel.EMPTY_ITERABLE;
     }
 
     @Override
-    public TemplateCollectionModel values() throws TemplateException {
-        return TemplateCollectionModel.EMPTY_COLLECTION;
+    public TemplateIterableModel values() throws TemplateException {
+        return TemplateIterableModel.EMPTY_ITERABLE;
     }
 
     @Override
@@ -46,7 +46,7 @@ class EmptyHashModel implements TemplateHashModelEx2, Serializable {
     }
 
     @Override
-    public boolean isEmpty() throws TemplateException {
+    public boolean isEmptyHash() throws TemplateException {
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIteratorModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIteratorModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIteratorModel.java
index a0b47e7..c2876c0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIteratorModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptyIteratorModel.java
@@ -27,7 +27,7 @@ class EmptyIteratorModel implements TemplateModelIterator, Serializable {
 
     @Override
     public TemplateModel next() throws TemplateException {
-        throw new TemplateException("The collection has no more elements.");
+        throw new TemplateException("It's an empty iterator it has no elements.");
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptySequenceModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptySequenceModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptySequenceModel.java
index b6a176e..bfd7930 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptySequenceModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/EmptySequenceModel.java
@@ -31,8 +31,18 @@ class EmptySequenceModel implements TemplateSequenceModel, Serializable {
     }
 
     @Override
-    public int size() throws TemplateException {
+    public int getCollectionSize() throws TemplateException {
         return 0;
     }
 
+    @Override
+    public boolean isEmptyCollection() throws TemplateException {
+        return true;
+    }
+
+    @Override
+    public TemplateModelIterator iterator() throws TemplateException {
+        return TemplateModelIterator.EMPTY_ITERATOR;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 e3d5c4a..3eba7a9 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
@@ -28,12 +28,12 @@ import org.apache.freemarker.core.TemplateException;
  * It is meant to be interpreted in the most sensible way possible in various contexts.
  * This can be returned to avoid exceptions.
  */
-
+// TODO [FM3] As `exp!` doesn't use this, are the other use cases necessary and correct?
 final class GeneralPurposeNothing
 implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, TemplateHashModelEx2,
         TemplateFunctionModel {
 
-    public static final TemplateModel INSTANCE = new GeneralPurposeNothing();
+    static final TemplateModel INSTANCE = new GeneralPurposeNothing();
 
     private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(
             0, true,
@@ -53,18 +53,28 @@ implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, Tem
     }
 
     @Override
-    public boolean isEmpty() {
+    public int getHashSize() throws TemplateException {
+        return 0;
+    }
+
+    @Override
+    public boolean isEmptyHash() {
         return true;
     }
 
     @Override
-    public int size() {
+    public int getCollectionSize() {
         return 0;
     }
 
     @Override
+    public boolean isEmptyCollection() throws TemplateException {
+        return true;
+    }
+
+    @Override
     public TemplateModel get(int i) throws TemplateException {
-        throw new TemplateException("Can't get item from an empty sequence.");
+        return null;
     }
 
     @Override
@@ -73,6 +83,11 @@ implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, Tem
     }
 
     @Override
+    public TemplateModelIterator iterator() throws TemplateException {
+        return TemplateModelIterator.EMPTY_ITERATOR;
+    }
+
+    @Override
     public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
         return null;
     }
@@ -83,13 +98,13 @@ implements TemplateBooleanModel, TemplateStringModel, TemplateSequenceModel, Tem
     }
 
     @Override
-    public TemplateCollectionModel keys() {
-        return TemplateCollectionModel.EMPTY_COLLECTION;
+    public TemplateIterableModel keys() {
+        return TemplateIterableModel.EMPTY_ITERABLE;
     }
 
     @Override
-    public TemplateCollectionModel values() {
-        return TemplateCollectionModel.EMPTY_COLLECTION;
+    public TemplateIterableModel values() {
+        return TemplateIterableModel.EMPTY_ITERABLE;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 d1db16c..1562b0a 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
@@ -19,34 +19,24 @@
 
 package org.apache.freemarker.core.model;
 
-import java.util.Collection;
-
 import org.apache.freemarker.core.TemplateException;
 
 /**
- * "collection" template language data type: a collection of values that can be enumerated, but can't be or not meant to
- * be accessed by index or key. As such, this is not a super-interface of {@link TemplateSequenceModel}, and
- * implementations of that interface needn't also implement this interface just because they can. They should though, if
- * enumeration with this interface is significantly faster than enumeration by index. The {@code #list} directive will
- * enumerate using this interface if it's available.
- * 
- * <p>
- * The enumeration should be repeatable if that's possible with reasonable effort, otherwise a second enumeration
- * attempt is allowed to throw an {@link TemplateException}. Generally, the interface user Java code need not
- * handle that kind of exception, as in practice only the template author can handle it, by not listing such collections
- * twice.
- * 
- * <p>
- * Note that to wrap Java's {@link Collection}, you should implement {@link TemplateCollectionModelEx}, not just this
- * interface.
+ * "collection" template language data type: Extends {@link TemplateIterableModel} with the ability to get the
+ * whether there's any element, and the ability to get number of elements in the collection.
  */
-public interface TemplateCollectionModel extends TemplateModel {
+public interface TemplateCollectionModel extends TemplateIterableModel {
 
-    TemplateCollectionModelEx EMPTY_COLLECTION = new EmptyCollectionExModel();
+    /**
+     * Returns the number items in this collection, or {@link Integer#MAX_VALUE}, if there are more than
+     * {@link Integer#MAX_VALUE} items.
+     */
+    int getCollectionSize() throws TemplateException;
 
     /**
-     * Retrieves a template model iterator that is used to iterate over the elements in this collection.
+     * Returns if the collection contains any elements. This differs from {@code getCollectionSize() != 0} only in that
+     * the exact number of items need not be calculated.
      */
-    TemplateModelIterator iterator() throws TemplateException;
+    boolean isEmptyCollection() throws TemplateException;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModelEx.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModelEx.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModelEx.java
deleted file mode 100644
index 730a267..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCollectionModelEx.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core.model;
-
-import java.util.Collection;
-
-import org.apache.freemarker.core.TemplateException;
-
-/**
- * "extended collection" template language data type: Adds size/emptiness querybility and "contains" test to
- * {@link TemplateCollectionModel}. The added extra operations is provided by all Java {@link Collection}-s, and
- * this interface was added to make that accessible for templates too.
- */
-public interface TemplateCollectionModelEx extends TemplateCollectionModel {
-
-    /**
-     * Returns the number items in this collection, or {@link Integer#MAX_VALUE}, if there are more than
-     * {@link Integer#MAX_VALUE} items.
-     */
-    int size() throws TemplateException;
-
-    /**
-     * Returns if the collection contains any elements. This differs from {@code size() != 0} only in that the exact
-     * number of items need not be calculated.
-     */
-    boolean isEmpty() throws TemplateException;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java
index bfdc118..3eb140d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java
@@ -47,7 +47,7 @@ public interface TemplateDirectiveModel extends TemplateCallableModel {
      *         call is not from a template, you can use {@link NonTemplateCallPlace#INSTANCE} (or another {@link
      *         NonTemplateCallPlace} instance). Note that {@link CallPlace#executeNestedContent(TemplateModel[], Writer,
      *         Environment)} can be used to execute the nested content (even if there's no nested content; then simply
-     *         nothing happens).
+     *         nothing happens), and to pass nested content parameters to it.
      * @param out
      *         Print the output here (if there's any)
      * @param env

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModel.java
index 8125233..d15d1fd 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateHashModel.java
@@ -41,5 +41,5 @@ public interface TemplateHashModel extends TemplateModel {
      */
     TemplateModel get(String key) throws TemplateException;
 
-    boolean isEmpty() throws TemplateException;
+    boolean isEmptyHash() throws TemplateException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 becb3c5..2a968c9 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
@@ -35,18 +35,17 @@ public interface TemplateHashModelEx extends TemplateHashModel {
     /**
      * @return the number of key/value mappings in the hash.
      */
-    int size() throws TemplateException;
+    int getHashSize() throws TemplateException;
 
     /**
-     * @return a collection containing the keys in the hash. Every element of 
-     *      the returned collection must implement the {@link TemplateStringModel}
-     *      (as the keys of hashes are always strings).
+     * @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).
      */
-    TemplateCollectionModel keys() throws TemplateException;
+    TemplateIterableModel keys() throws TemplateException;
 
     /**
-     * @return a collection containing the values in the hash. The elements of the
-     * returned collection can be any kind of {@link TemplateModel}-s.
+     * @return An iterable returning the values in the hash. The elements returned by the iterable can be any kind of
+     * {@link TemplateModel}-s.
      */
-    TemplateCollectionModel values() throws TemplateException;
+    TemplateIterableModel values() throws TemplateException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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
new file mode 100644
index 0000000..7d67f08
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateIterableModel.java
@@ -0,0 +1,49 @@
+/*
+ * 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 java.util.Collection;
+
+import org.apache.freemarker.core.TemplateException;
+
+/**
+ * "iterable" template language data type: a collection of values that can be listed; this interface doesn't add
+ * the ability of getting the number of elements, or to return elements by index.
+ * 
+ * <p>
+ * The enumeration should be repeatable if that's possible with reasonable effort, otherwise a second enumeration
+ * attempt is allowed to throw an {@link TemplateException}. Generally, the interface user Java code need not
+ * handle that kind of exception, as in practice only the template author can handle it, by not listing such collections
+ * twice.
+ * 
+ * <p>
+ * Note that to wrap Java's {@link Collection}, you should implement {@link TemplateCollectionModel}, not just this
+ * interface.
+ */
+public interface TemplateIterableModel extends TemplateModel {
+
+    TemplateCollectionModel EMPTY_ITERABLE = new EmptyCollectionModel();
+
+    /**
+     * Retrieves an iterator that is used to iterate over the elements of something.
+     */
+    TemplateModelIterator iterator() throws TemplateException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModelIterator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModelIterator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModelIterator.java
index cd24cbb..4f70a5b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModelIterator.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModelIterator.java
@@ -19,20 +19,33 @@
 
 package org.apache.freemarker.core.model;
 
+import java.util.List;
+import java.util.NoSuchElementException;
+
 import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.impl.DefaultListAdapter;
 
 /**
- * Used to iterate over a set of template models <em>once</em>; usually returned from
- * {@link TemplateCollectionModel#iterator()}. Note that it's not a {@link TemplateModel}.
+ * Used to iterate over a set of template models <em>once</em>; usually returned from {@link
+ * TemplateIterableModel#iterator()}. Note that it's not a {@link TemplateModel}. Note that the implementation of this
+ * interface may assume that the collection of elements that we iterate through is not changing after the {@link
+ * TemplateModelIterator} was created, as far as the {@link TemplateModelIterator} is still in use. If they still
+ * change, the methods of this interface might throw any kind of exception or gives and inconsistent view of the
+ * elements (like partially old element, partially new elements). Of course, implementations of this interface may
+ * specify a more specific behavior. Notably, the {@link TemplateModelIterator} return by {@link
+ * DefaultListAdapter#iterator()} gives the same concurrency guarantees as the wrapped {@link List} object.
  */
 public interface TemplateModelIterator {
 
     TemplateModelIterator EMPTY_ITERATOR = new EmptyIteratorModel();
 
     /**
-     * Returns the next model.
-     * @throws TemplateException if the next model can not be retrieved
-     *   (i.e. because the iterator is exhausted).
+     * Returns the next item. It must not be called if there are no more items, as the behavior is undefined then
+     * (typically, {@link NoSuchElementException} or {@link IndexOutOfBoundsException} will be thrown, or {@code null}
+     * will be returned). Hence, you should almost always call {@link #hasNext()} before this method, and only call this
+     * method if that has returned {@code true}. (Note that the implementation still can't assume that {@link
+     * #hasNext()} is always called before {@link #next()}; the caller might knows that there's a next item for a
+     * different reason, like already knows the size of the collection.)
      */
     TemplateModel next() throws TemplateException;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateSequenceModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateSequenceModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateSequenceModel.java
index d9dc6c6..6fd1903 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateSequenceModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateSequenceModel.java
@@ -24,29 +24,26 @@ import org.apache.freemarker.core.TemplateException;
 /**
  * "sequence" template language data type; an object that contains other objects accessible through an integer 0-based
  * index.
- * 
  * <p>
  * Used in templates like: {@code mySeq[index]}, {@code <#list mySeq as i>...</#list>}, {@code mySeq?size}, etc.
- * 
- * @see TemplateCollectionModel
+ *
+ * @see TemplateIterableModel
  */
-public interface TemplateSequenceModel extends TemplateModel {
+public interface TemplateSequenceModel extends TemplateCollectionModel {
 
     TemplateSequenceModel EMPTY_SEQUENCE = new EmptySequenceModel();
 
     /**
-     * Retrieves the i-th template model in this sequence.
-     * 
+     * Retrieves the template model at the given index, or {@code null} if the index is out of bounds. If index-based
+     * access on the backing data structure is not very efficient (say, it's O(N) and you known N can be big), then you
+     * should consider only implementing {@link TemplateCollectionModel} instead. Also, if you need to list all items,
+     * you shouldn't use this method, but {@link TemplateIterableModel#iterator()}.
+     *
      * @return the item at the specified index, or <code>null</code> if the index is out of bounds. Note that a
-     *         <code>null</code> value is interpreted by FreeMarker as "variable does not exist", and accessing a
-     *         missing variables is usually considered as an error in the FreeMarker Template Language, so the usage of
-     *         a bad index will not remain hidden, unless the default value for that case was also specified in the
-     *         template.
+     * <code>null</code> value is interpreted by FreeMarker as "variable does not exist", and accessing a missing
+     * variables is usually considered as an error in the template language, so the usage of a bad index will not remain
+     * hidden, unless the default value for that case was also specified in the template.
      */
     TemplateModel get(int index) throws TemplateException;
 
-    /**
-     * @return the number of items in the list.
-     */
-    int size() throws TemplateException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 1b779d5..06dd2c0 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.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx;
 import org.apache.freemarker.core.model.TemplateModel;
@@ -76,7 +76,7 @@ public class BeanModel
     /**
      * Creates a new model that wraps the specified object. Note that there are
      * specialized subclasses of this class for wrapping arrays, collections,
-     * enumeration, iterators, and maps. Note also that the superclass can be
+     * enumeration, iterators, maps, etc. Note also that the superclass can be
      * used to wrap String objects if only {@link TemplateStringModel} functionality is needed. You
      * can also choose to delegate the choice over which model class is used for
      * wrapping to {@link DefaultObjectWrapper#wrap(Object)}.
@@ -189,8 +189,8 @@ public class BeanModel
                 // cachedModel remains null, as we don't cache these
             } else if (desc instanceof IndexedPropertyDescriptor) {
                 // In FreeMarker 2 we have exposed such indexed properties as sequences, but they can't support
-                // the size() method, so we have discontinued that. People has to call the indexed read method like
-                // any other method.
+                // the getCollectionSize() method, so we have discontinued that. People has to call the indexed read
+                // method like any other method.
                 resultModel = UNKNOWN;
             } else {
                 throw new IllegalStateException("PropertyDescriptor.readMethod shouldn't be null");
@@ -251,7 +251,7 @@ public class BeanModel
      * {@link Map}, or an {@link Iterator} that has no more items, or a {@link Boolean#FALSE}, or {@code null}. 
      */
     @Override
-    public boolean isEmpty() {
+    public boolean isEmptyHash() {
         if (object instanceof String) {
             return ((String) object).length() == 0;
         }
@@ -283,24 +283,24 @@ public class BeanModel
     }
     
     @Override
-    public int size() {
+    public int getHashSize() {
         return wrapper.getClassIntrospector().keyCount(object.getClass());
     }
 
     @Override
-    public TemplateCollectionModel keys() {
-        return new CollectionAndSequence(new SimpleSequence(keySet(), wrapper));
+    public TemplateIterableModel keys() {
+        return new IterableAndSequence(DefaultNonListCollectionAdapter.adapt(keySet(), wrapper));
     }
 
     @Override
-    public TemplateCollectionModel values() throws TemplateException {
-        List<Object> values = new ArrayList<>(size());
+    public TemplateIterableModel values() throws TemplateException {
+        List<Object> values = new ArrayList<>(getHashSize());
         TemplateModelIterator it = keys().iterator();
         while (it.hasNext()) {
             String key = ((TemplateStringModel) it.next()).getAsString();
             values.add(get(key));
         }
-        return new CollectionAndSequence(new SimpleSequence(values, wrapper));
+        return new IterableAndSequence(DefaultNonListCollectionAdapter.adapt(values, wrapper));
     }
     
     @Override
@@ -314,7 +314,7 @@ public class BeanModel
      * interface. Subclasses that override <tt>invokeGenericGet</tt> to
      * provide additional hash keys should also override this method.
      */
-    protected Set/*<Object>*/ keySet() {
+    protected Set<String> keySet() {
         return wrapper.getClassIntrospector().keySet(object.getClass());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassBasedModelFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassBasedModelFactory.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassBasedModelFactory.java
index ac055b4..31701cb 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassBasedModelFactory.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ClassBasedModelFactory.java
@@ -136,7 +136,7 @@ abstract class ClassBasedModelFactory implements TemplateHashModel {
     }
 
     @Override
-    public boolean isEmpty() {
+    public boolean isEmptyHash() {
         return false;
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 a1f5935..cc083d4 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
@@ -1007,12 +1007,14 @@ class ClassIntrospector {
      * Returns the Set of names of introspected methods/properties that should be available via the TemplateHashModel
      * interface.
      */
-    Set<Object> keySet(Class<?> clazz) {
+    // TODO [FM3] Can't we instead return an Iterable<String> that filters out the non-String keys?
+    @SuppressWarnings("rawtypes")
+    Set<String> keySet(Class<?> clazz) {
         Set<Object> set = new HashSet<>(get(clazz).keySet());
         set.remove(CONSTRUCTORS_KEY);
         set.remove(GENERIC_GET_KEY);
         set.remove(ARG_TYPES_BY_METHOD_KEY);
-        return set;
+        return (Set) set;
     }
 
     // -----------------------------------------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAdapter.java
deleted file mode 100644
index 10f2091..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAdapter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core.model.impl;
-
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelAdapter;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.util.UndeclaredThrowableException;
-
-/**
- * Adapts a {@link TemplateCollectionModel} to  {@link Collection}.
- */
-class CollectionAdapter extends AbstractCollection implements TemplateModelAdapter {
-    private final DefaultObjectWrapper wrapper;
-    private final TemplateCollectionModel model;
-    
-    CollectionAdapter(TemplateCollectionModel model, DefaultObjectWrapper wrapper) {
-        this.model = model;
-        this.wrapper = wrapper;
-    }
-    
-    @Override
-    public TemplateModel getTemplateModel() {
-        return model;
-    }
-    
-    @Override
-    public int size() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Iterator iterator() {
-        try {
-            return new Iterator() {
-                final TemplateModelIterator i = model.iterator();
-    
-                @Override
-                public boolean hasNext() {
-                    try {
-                        return i.hasNext();
-                    } catch (TemplateException e) {
-                        throw new UndeclaredThrowableException(e);
-                    }
-                }
-                
-                @Override
-                public Object next() {
-                    try {
-                        return wrapper.unwrap(i.next());
-                    } catch (TemplateException e) {
-                        throw new UndeclaredThrowableException(e);
-                    }
-                }
-                
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
-                }
-            };
-        } catch (TemplateException e) {
-            throw new UndeclaredThrowableException(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAndSequence.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAndSequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAndSequence.java
deleted file mode 100644
index 8a7970a..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/CollectionAndSequence.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core.model.impl;
-
-import java.util.ArrayList;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-
-/**
- * Add sequence capabilities to an existing collection, or
- * vice versa. Used by ?keys and ?values built-ins.
- */
-// [FM3] FTL sequence should extend FTL collection, so we shouldn't need that direction, only the other.
-final public class CollectionAndSequence implements TemplateCollectionModel, TemplateSequenceModel {
-    private TemplateCollectionModel collection;
-    private TemplateSequenceModel sequence;
-    private ArrayList data;
-
-    public CollectionAndSequence(TemplateCollectionModel collection) {
-        this.collection = collection;
-    }
-
-    public CollectionAndSequence(TemplateSequenceModel sequence) {
-        this.sequence = sequence;
-    }
-
-    @Override
-    public TemplateModelIterator iterator() throws TemplateException {
-        if (collection != null) {
-            return collection.iterator();
-        } else {
-            return new SequenceIterator(sequence);
-        }
-    }
-
-    @Override
-    public TemplateModel get(int i) throws TemplateException {
-        if (sequence != null) {
-            return sequence.get(i);
-        } else {
-            initSequence();
-            return (TemplateModel) data.get(i);
-        }
-    }
-
-    @Override
-    public int size() throws TemplateException {
-        if (sequence != null) {
-            return sequence.size();
-        } else if (collection instanceof TemplateCollectionModelEx) {
-            return ((TemplateCollectionModelEx) collection).size();
-        } else {
-            initSequence();
-            return data.size();
-        }
-    }
-
-    private void initSequence() throws TemplateException {
-        if (data == null) {
-            data = new ArrayList();
-            TemplateModelIterator it = collection.iterator();
-            while (it.hasNext()) {
-                data.add(it.next());
-            }
-        }
-    }
-
-    private static class SequenceIterator
-    implements TemplateModelIterator {
-        private final TemplateSequenceModel sequence;
-        private final int size;
-        private int index = 0;
-
-        SequenceIterator(TemplateSequenceModel sequence) throws TemplateException {
-            this.sequence = sequence;
-            size = sequence.size();
-            
-        }
-        @Override
-        public TemplateModel next() throws TemplateException {
-            return sequence.get(index++);
-        }
-
-        @Override
-        public boolean hasNext() {
-            return index < size;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultArrayAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultArrayAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultArrayAdapter.java
index 0e15194..06816fd 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultArrayAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultArrayAdapter.java
@@ -27,6 +27,7 @@ import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 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.TemplateSequenceModel;
 import org.apache.freemarker.core.model.WrapperTemplateModel;
 import org.apache.freemarker.core.model.WrappingTemplateModel;
@@ -122,11 +123,33 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -144,14 +167,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Byte.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
+
+        @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
         @Override
         public Object getWrappedObject() {
             return array;
@@ -170,15 +216,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Short.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -196,15 +264,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Integer.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -222,15 +312,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Long.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -248,15 +360,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Float.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -274,15 +408,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Double.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -300,15 +456,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Character.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -326,15 +504,37 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
 
         @Override
         public TemplateModel get(int index) throws TemplateException {
-            return index >= 0 && index < array.length ? wrap(Boolean.valueOf(array[index])) : null;
+            return index >= 0 && index < array.length ? wrap(array[index]) : null;
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return array.length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return array.length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(array[nextIndex++]);
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < array.length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }
@@ -361,11 +561,33 @@ public abstract class DefaultArrayAdapter extends WrappingTemplateModel implemen
         }
 
         @Override
-        public int size() throws TemplateException {
+        public int getCollectionSize() throws TemplateException {
             return length;
         }
 
         @Override
+        public boolean isEmptyCollection() throws TemplateException {
+            return length == 0;
+        }
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateException {
+            return new TemplateModelIterator() {
+                private int nextIndex;
+
+                @Override
+                public TemplateModel next() throws TemplateException {
+                    return wrap(Array.get(array, nextIndex++));
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateException {
+                    return nextIndex < length;
+                }
+            };
+        }
+
+        @Override
         public Object getWrappedObject() {
             return array;
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultEnumerationAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultEnumerationAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultEnumerationAdapter.java
index af61102..428d7f8 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultEnumerationAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultEnumerationAdapter.java
@@ -26,7 +26,7 @@ import org.apache.freemarker.core.TemplateException;
 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.TemplateCollectionModel;
+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;
@@ -37,11 +37,11 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Adapts an {@link Enumeration} to the corresponding {@link TemplateModel} interface(s), most importantly to
- * {@link TemplateCollectionModel}. Putting aside that it wraps an {@link Enumeration} instead of an {@link Iterator},
+ * {@link TemplateIterableModel}. Putting aside that it wraps an {@link Enumeration} instead of an {@link Iterator},
  * this is identical to {@link DefaultIteratorAdapter}, so see further details there.
  */
 @SuppressWarnings("serial")
-public class DefaultEnumerationAdapter extends WrappingTemplateModel implements TemplateCollectionModel,
+public class DefaultEnumerationAdapter extends WrappingTemplateModel implements TemplateIterableModel,
         AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
 
     @SuppressFBWarnings(value="SE_BAD_FIELD", justification="We hope it's Seralizable")
@@ -98,10 +98,6 @@ public class DefaultEnumerationAdapter extends WrappingTemplateModel implements
                 enumerationOwnedByMe = true;
             }
 
-            if (!enumeration.hasMoreElements()) {
-                throw new TemplateException("The collection has no more items.");
-            }
-
             Object value = enumeration.nextElement();
             return value instanceof TemplateModel ? (TemplateModel) value : wrap(value);
         }
@@ -119,7 +115,7 @@ public class DefaultEnumerationAdapter extends WrappingTemplateModel implements
         private void checkNotOwner() throws TemplateException {
             if (enumerationOwnedBySomeone) {
                 throw new TemplateException(
-                        "This collection value wraps a java.util.Enumeration, thus it can be listed only once.");
+                        "This iterator value wraps a java.util.Enumeration, thus it can be listed only once.");
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIterableAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIterableAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIterableAdapter.java
index e60a090..82dd9eb 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIterableAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIterableAdapter.java
@@ -27,7 +27,7 @@ import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.ObjectWrapperWithAPISupport;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
+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;
@@ -36,7 +36,7 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
 
 /**
  * Adapts an {@link Iterable} to the corresponding {@link TemplateModel} interface(s), most importantly to
- * {@link TemplateCollectionModel}. This should only be used if {@link Collection} is not implemented by the adapted
+ * {@link TemplateIterableModel}. This should only be used if {@link Collection} is not implemented by the adapted
  * object, because then {@link DefaultListAdapter} and {@link DefaultNonListCollectionAdapter} gives more functionality.
  * 
  * <p>
@@ -45,7 +45,7 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
  * {@link Iterator} modifier methods (though of course, Java methods called from the template can violate this rule).
  */
 @SuppressWarnings("serial")
-public class DefaultIterableAdapter extends WrappingTemplateModel implements TemplateCollectionModel,
+public class DefaultIterableAdapter extends WrappingTemplateModel implements TemplateIterableModel,
         AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
     
     private final Iterable<?> iterable;
@@ -54,7 +54,7 @@ public class DefaultIterableAdapter extends WrappingTemplateModel implements Tem
      * Factory method for creating new adapter instances.
      * 
      * @param iterable
-     *            The collection to adapt; can't be {@code null}.
+     *            The {@link Iterable} to adapt; can't be {@code null}.
      * @param wrapper
      *            The {@link ObjectWrapper} used to wrap the items in the array. Has to be
      *            {@link ObjectWrapperAndUnwrapper} because of planned future features.
@@ -70,7 +70,7 @@ public class DefaultIterableAdapter extends WrappingTemplateModel implements Tem
 
     @Override
     public TemplateModelIterator iterator() throws TemplateException {
-        return new DefaultUnassignableIteratorAdapter(iterable.iterator(), getObjectWrapper());
+        return new IteratorToTemplateModelIteratorAdapter(iterable.iterator(), getObjectWrapper());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIteratorAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIteratorAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIteratorAdapter.java
index ea9af3f..e727fa3 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIteratorAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultIteratorAdapter.java
@@ -25,7 +25,7 @@ import org.apache.freemarker.core.TemplateException;
 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.TemplateCollectionModel;
+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;
@@ -36,7 +36,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Adapts an {@link Iterator} to the corresponding {@link TemplateModel} interface(s), most importantly to
- * {@link TemplateCollectionModel}. The resulting {@link TemplateCollectionModel} can only be listed (iterated) once.
+ * {@link TemplateIterableModel}. The resulting {@link TemplateIterableModel} can only be listed (iterated) once.
  * If the user tries list the variable for a second time, an exception will be thrown instead of silently gettig an
  * empty (or partial) listing.
  * 
@@ -49,7 +49,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * This adapter is used by {@link DefaultObjectWrapper} if its {@code useAdaptersForCollections} property is
  * {@code true}, which is the default when its {@code incompatibleImprovements} property is 2.3.22 or higher.
  */
-public class DefaultIteratorAdapter extends WrappingTemplateModel implements TemplateCollectionModel,
+public class DefaultIteratorAdapter extends WrappingTemplateModel implements TemplateIterableModel,
         AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
 
     @SuppressFBWarnings(value="SE_BAD_FIELD", justification="We hope it's Seralizable")
@@ -106,10 +106,6 @@ public class DefaultIteratorAdapter extends WrappingTemplateModel implements Tem
                 iteratorOwnedByMe = true;
             }
 
-            if (!iterator.hasNext()) {
-                throw new TemplateException("The collection has no more items.");
-            }
-
             Object value = iterator.next();
             return value instanceof TemplateModel ? (TemplateModel) value : wrap(value);
         }
@@ -127,7 +123,7 @@ public class DefaultIteratorAdapter extends WrappingTemplateModel implements Tem
         private void checkNotOwner() throws TemplateException {
             if (iteratorOwnedBySomeone) {
                 throw new TemplateException(
-                        "This collection value wraps a java.util.Iterator, thus it can be listed only once.");
+                        "This value wraps a java.util.Iterator, thus it can be listed only once.");
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultListAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultListAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultListAdapter.java
index 80e76d8..32b01ac 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultListAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultListAdapter.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core.model.impl;
 
-import java.util.AbstractSequentialList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.freemarker.core.TemplateException;
@@ -27,7 +27,6 @@ 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.RichObjectWrapper;
-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.TemplateModelWithAPISupport;
@@ -41,9 +40,11 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
  * specifically to be used from a template, also consider using {@link SimpleSequence} (see comparison there).
  * 
  * <p>
- * Thread safety: A {@link DefaultListAdapter} is as thread-safe as the {@link List} that it wraps is. Normally you only
- * have to consider read-only access, as the FreeMarker template language doesn't allow writing these sequences (though
- * of course, Java methods called from the template can violate this rule).
+ * Thread safety: A {@link DefaultListAdapter} is as thread-safe as the {@link List} that it wraps is. Also,
+ * {@link #iterator()} will return a {@link TemplateModelIterator} that is as thread-safe as the {@link Iterator}
+ * that the wrapped {@link List} returns.
+ * Note that normally you only have to consider read-only access, as the FreeMarker template language doesn't allow
+ * writing these sequences (though of course, Java methods called from the template can violate this rule).
  * 
  * <p>
  * This adapter is used by {@link DefaultObjectWrapper} if its {@code useAdaptersForCollections} property is
@@ -67,10 +68,7 @@ public class DefaultListAdapter extends WrappingTemplateModel implements Templat
      *            The {@link ObjectWrapper} used to wrap the items in the array.
      */
     public static DefaultListAdapter adapt(List list, RichObjectWrapper wrapper) {
-        // [2.4] DefaultListAdapter should implement TemplateCollectionModelEx, so this choice becomes unnecessary
-        return list instanceof AbstractSequentialList
-                ? new DefaultListAdapterWithCollectionSupport(list, wrapper)
-                : new DefaultListAdapter(list, wrapper);
+        return new DefaultListAdapter(list, wrapper);
     }
 
     private DefaultListAdapter(List list, RichObjectWrapper wrapper) {
@@ -84,11 +82,21 @@ public class DefaultListAdapter extends WrappingTemplateModel implements Templat
     }
 
     @Override
-    public int size() throws TemplateException {
+    public int getCollectionSize() throws TemplateException {
         return list.size();
     }
 
     @Override
+    public boolean isEmptyCollection() throws TemplateException {
+        return list.isEmpty();
+    }
+
+    @Override
+    public TemplateModelIterator iterator() throws TemplateException {
+        return new IteratorToTemplateModelIteratorAdapter(list.iterator(), getObjectWrapper());
+    }
+
+    @Override
     public Object getAdaptedObject(Class hint) {
         return getWrappedObject();
     }
@@ -98,20 +106,6 @@ public class DefaultListAdapter extends WrappingTemplateModel implements Templat
         return list;
     }
 
-    private static class DefaultListAdapterWithCollectionSupport extends DefaultListAdapter implements
-            TemplateCollectionModel {
-
-        private DefaultListAdapterWithCollectionSupport(List list, RichObjectWrapper wrapper) {
-            super(list, wrapper);
-        }
-
-        @Override
-        public TemplateModelIterator iterator() throws TemplateException {
-            return new DefaultUnassignableIteratorAdapter(list.iterator(), getObjectWrapper());
-        }
-
-    }
-
     @Override
     public TemplateModel getAPI() throws TemplateException {
         return ((ObjectWrapperWithAPISupport) getObjectWrapper()).wrapAsAPI(list);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/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 832c675..f663990 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.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateIterableModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
 import org.apache.freemarker.core.model.TemplateModel;
@@ -124,23 +124,23 @@ public class DefaultMapAdapter extends WrappingTemplateModel
     }
 
     @Override
-    public boolean isEmpty() {
+    public boolean isEmptyHash() {
         return map.isEmpty();
     }
 
     @Override
-    public int size() {
+    public int getHashSize() {
         return map.size();
     }
 
     @Override
-    public TemplateCollectionModel keys() {
-        return new SimpleCollection(map.keySet(), getObjectWrapper());
+    public TemplateIterableModel keys() {
+        return new SimpleIterable(map.keySet(), getObjectWrapper());
     }
 
     @Override
-    public TemplateCollectionModel values() {
-        return new SimpleCollection(map.values(), getObjectWrapper());
+    public TemplateIterableModel values() {
+        return new SimpleIterable(map.values(), getObjectWrapper());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/cae86e18/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultNonListCollectionAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultNonListCollectionAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultNonListCollectionAdapter.java
index 6f8a5f9..74d74d8 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultNonListCollectionAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultNonListCollectionAdapter.java
@@ -27,7 +27,7 @@ import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.ObjectWrapperWithAPISupport;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
+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.TemplateModelWithAPISupport;
@@ -36,7 +36,7 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
 
 /**
  * Adapts a non-{@link List} Java {@link Collection} to the corresponding {@link TemplateModel} interface(s), most
- * importantly to {@link TemplateCollectionModelEx}. For {@link List}-s, use {@link DefaultListAdapter}, or else you
+ * importantly to {@link TemplateCollectionModel}. For {@link List}-s, use {@link DefaultListAdapter}, or else you
  * lose indexed element access.
  * 
  * <p>
@@ -44,7 +44,7 @@ import org.apache.freemarker.core.model.WrappingTemplateModel;
  * is. Normally you only have to consider read-only access, as the FreeMarker template language doesn't allow writing
  * these collections (though of course, Java methods called from the template can violate this rule).
  */
-public class DefaultNonListCollectionAdapter extends WrappingTemplateModel implements TemplateCollectionModelEx,
+public class DefaultNonListCollectionAdapter extends WrappingTemplateModel implements TemplateCollectionModel,
         AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport {
 
     private final Collection collection;
@@ -69,16 +69,16 @@ public class DefaultNonListCollectionAdapter extends WrappingTemplateModel imple
 
     @Override
     public TemplateModelIterator iterator() throws TemplateException {
-        return new DefaultUnassignableIteratorAdapter(collection.iterator(), getObjectWrapper());
+        return new IteratorToTemplateModelIteratorAdapter(collection.iterator(), getObjectWrapper());
     }
 
     @Override
-    public int size() {
+    public int getCollectionSize() {
         return collection.size();
     }
 
     @Override
-    public boolean isEmpty() {
+    public boolean isEmptyCollection() {
         return collection.isEmpty();
     }