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 2018/03/01 17:08:39 UTC
[3/4] incubator-freemarker git commit: TemplateHashModelAdapter
improvements (esp. that it utilizes KeyValuePairIterator)
TemplateHashModelAdapter improvements (esp. that it utilizes KeyValuePairIterator)
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/9d96369e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/9d96369e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/9d96369e
Branch: refs/heads/3
Commit: 9d96369ebde23d6e0a90862e3dfd0ff98c8242b1
Parents: 654fdad
Author: ddekany <dd...@apache.org>
Authored: Thu Mar 1 17:10:04 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Thu Mar 1 17:10:04 2018 +0100
----------------------------------------------------------------------
.../impl/TemplateHashModelAdapterTest.java | 95 ++++++++++++++++++++
.../model/impl/TemplateHashModelAdapter.java | 86 ++++++++++++------
2 files changed, 155 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9d96369e/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapterTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapterTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapterTest.java
new file mode 100644
index 0000000..6b6e51a
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapterTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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 static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.ObjectWrappingException;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.junit.Test;
+
+public class TemplateHashModelAdapterTest {
+
+ @Test
+ public void testNonEmpty() throws ObjectWrappingException {
+ Map<Object, Object> map = new LinkedHashMap<Object, Object>();
+ map.put("k1", "v1");
+ map.put("k2", 2);
+ map.put("k3", null);
+ map.put(4, "v4");
+ map.put(null, "v5");
+ map.put("k6", true);
+
+ DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+ TemplateHashModel model = (TemplateHashModel) dow.wrap(map);
+
+ TemplateHashModelAdapter<Object, Object> adapted = new TemplateHashModelAdapter<Object, Object>(model, dow);
+
+ assertEquals("v1", adapted.get("k1"));
+ assertEquals(2, adapted.get("k2"));
+ assertNull(adapted.get("k3"));
+ assertNull(adapted.get(4)); // Because it's not a string key
+ assertNull(adapted.get(null)); // Because it's not a string key
+ assertEquals(true, adapted.get("k6"));
+
+ assertArrayEquals(new Object[] { "k1", "k2", "k3", 4, null, "k6" }, adapted.keySet().toArray());
+ assertArrayEquals(new Object[] { "v1", 2, null, "v4", "v5", true }, adapted.values().toArray());
+ assertArrayEquals(
+ new Object[] {
+ Pair.of("k1", "v1"),
+ Pair.of("k2", 2),
+ Pair.of("k3", null),
+ Pair.of(4, "v4"),
+ Pair.of(null, "v5"),
+ Pair.of("k6", true)
+ },
+ adapted.entrySet().toArray());
+
+ assertEquals(map.size(), adapted.size());
+ assertEquals(map.isEmpty(), adapted.isEmpty());
+ }
+
+ @Test
+ public void testEmpty() throws ObjectWrappingException {
+ Map<Object, Object> map = Collections.emptyMap();
+
+ DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+ TemplateHashModel model = (TemplateHashModel) dow.wrap(map);
+
+ TemplateHashModelAdapter<Object, Object> adapted = new TemplateHashModelAdapter<Object, Object>(model, dow);
+
+ assertNull(adapted.get("k1"));
+
+ assertThat(adapted.keySet(), empty());
+ assertThat(adapted.values(), empty());
+ assertThat(adapted.entrySet(), empty());
+
+ assertEquals(map.size(), adapted.size());
+ assertEquals(map.isEmpty(), adapted.isEmpty());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/9d96369e/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapter.java
index 5f8a528..7197b6e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapter.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateHashModelAdapter.java
@@ -29,18 +29,19 @@ import java.util.Set;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.TemplateHashModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePair;
+import org.apache.freemarker.core.model.TemplateHashModelEx.KeyValuePairIterator;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelAdapter;
-import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.util.UndeclaredThrowableException;
/**
* Adapts a {@link TemplateHashModel} to a {@link Map}.
*/
-class TemplateHashModelAdapter extends AbstractMap implements TemplateModelAdapter {
+class TemplateHashModelAdapter<K, V> extends AbstractMap<K, V> implements TemplateModelAdapter {
private final DefaultObjectWrapper wrapper;
private final TemplateHashModel model;
- private Set entrySet;
+ private Set<Map.Entry<K, V>> entrySet;
TemplateHashModelAdapter(TemplateHashModel model, DefaultObjectWrapper wrapper) {
this.model = model;
@@ -61,10 +62,15 @@ class TemplateHashModelAdapter extends AbstractMap implements TemplateModelAdapt
}
}
+ @SuppressWarnings("unchecked")
@Override
- public Object get(Object key) {
+ public V get(Object key) {
+ // TODO [FM3] This restriction must be removed when TemplateHashModel allows non-string keys.
+ if (!(key instanceof String)) {
+ return null;
+ }
try {
- return wrapper.unwrap(model.get(String.valueOf(key)));
+ return (V) wrapper.unwrap(model.get((String) key));
} catch (TemplateException e) {
throw new UndeclaredThrowableException(e);
}
@@ -89,75 +95,103 @@ class TemplateHashModelAdapter extends AbstractMap implements TemplateModelAdapt
}
@Override
- public Set entrySet() {
+ public Set<Map.Entry<K, V>> entrySet() {
if (entrySet != null) {
return entrySet;
}
- return entrySet = new AbstractSet() {
+ return entrySet = new AbstractSet<Map.Entry<K, V>>() {
@Override
- public Iterator iterator() {
- final TemplateModelIterator iterator;
+ public Iterator<Map.Entry<K, V>> iterator() {
+ final KeyValuePairIterator kvpIter;
try {
- iterator = getModelEx().keys().iterator();
+ kvpIter = getModelEx().keyValuePairIterator();
} catch (TemplateException e) {
throw new UndeclaredThrowableException(e);
}
- return new Iterator() {
+ return new Iterator<Map.Entry<K, V>>() {
@Override
public boolean hasNext() {
try {
- return iterator.hasNext();
+ return kvpIter.hasNext();
} catch (TemplateException e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
- public Object next() {
- final Object key;
+ public Map.Entry<K, V> next() {
+ final KeyValuePair kvp;
try {
- if (!iterator.hasNext()) {
+ if (!kvpIter.hasNext()) {
throw new NoSuchElementException();
}
- key = wrapper.unwrap(iterator.next());
+ kvp = kvpIter.next();
} catch (TemplateException e) {
throw new UndeclaredThrowableException(e);
}
- return new Map.Entry() {
+ return new Map.Entry<K, V>() {
+ private boolean keyCalculated;
+ private K key;
+
+ private boolean valueCalculated;
+ private V value;
+
+ @SuppressWarnings("unchecked")
@Override
- public Object getKey() {
- return key;
+ public K getKey() {
+ if (!keyCalculated) {
+ try {
+ key = (K) wrapper.unwrap(kvp.getKey());;
+ } catch (TemplateException e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ keyCalculated = true;
+ }
+ return key;
}
+ @SuppressWarnings("unchecked")
@Override
- public Object getValue() {
- return get(key);
+ public V getValue() {
+ if (!valueCalculated) {
+ try {
+ value = (V) wrapper.unwrap(kvp.getValue());;
+ } catch (TemplateException e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ valueCalculated = true;
+ }
+ return value;
}
@Override
- public Object setValue(Object value) {
+ public V setValue(Object value) {
throw new UnsupportedOperationException();
}
+ @SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
+ if (!(o instanceof Map.Entry)) {
return false;
- Map.Entry e = (Map.Entry) o;
+ }
+ Map.Entry<K, V> e = (Map.Entry <K, V>) o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
- if (v1 == v2 || (v1 != null && v1.equals(v2)))
+ if (v1 == v2 || (v1 != null && v1.equals(v2))) {
return true;
+ }
}
return false;
}
@Override
public int hashCode() {
- Object value = getValue();
+ K key = getKey();
+ V value = getValue();
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}