| /* |
| * 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 freemarker.template; |
| |
| import static freemarker.test.hamcerst.Matchers.*; |
| import static org.hamcrest.Matchers.*; |
| import static org.junit.Assert.*; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| import java.util.Vector; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.junit.Test; |
| import org.w3c.dom.Document; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| |
| import freemarker.ext.beans.BeansWrapper; |
| import freemarker.ext.beans.EnumerationModel; |
| import freemarker.ext.beans.HashAdapter; |
| import freemarker.ext.util.WrapperTemplateModel; |
| |
| public class DefaultObjectWrapperTest { |
| |
| private final static DefaultObjectWrapper OW0 = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_0) |
| .build(); |
| |
| private final static DefaultObjectWrapper OW22 = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_22) |
| .build(); |
| |
| private final static DefaultObjectWrapper OW22NM = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| static { |
| OW22NM.setNullModel(NullModel.INSTANCE); |
| } |
| |
| private final static DefaultObjectWrapper OW22CA = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| static { |
| OW22CA.setForceLegacyNonListCollections(false); |
| } |
| |
| private final static DefaultObjectWrapper OW22IS = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| static { |
| OW22IS.setIterableSupport(true); |
| } |
| |
| @Test |
| public void testIncompatibleImprovementsVersionBreakPoints() throws Exception { |
| List<Version> expected = new ArrayList<Version>(); |
| for (int u = 0; u < 21; u++) { |
| expected.add(Configuration.VERSION_2_3_0); |
| } |
| expected.add(Configuration.VERSION_2_3_21); |
| expected.add(Configuration.VERSION_2_3_22); |
| expected.add(Configuration.VERSION_2_3_22); // no non-BC change in 2.3.23 |
| expected.add(Configuration.VERSION_2_3_24); |
| expected.add(Configuration.VERSION_2_3_24); // no non-BC change in 2.3.25 |
| expected.add(Configuration.VERSION_2_3_26); |
| expected.add(Configuration.VERSION_2_3_27); |
| |
| List<Version> actual = new ArrayList<Version>(); |
| for (int i = _TemplateAPI.VERSION_INT_2_3_0; i <= Configuration.getVersion().intValue(); i++) { |
| int major = i / 1000000; |
| int minor = i % 1000000 / 1000; |
| int micro = i % 1000; |
| final Version version = new Version(major, minor, micro); |
| final Version normalizedVersion = DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(version); |
| actual.add(normalizedVersion); |
| |
| final DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(version); |
| assertEquals(normalizedVersion, builder.getIncompatibleImprovements()); |
| assertEquals(normalizedVersion, builder.build().getIncompatibleImprovements()); |
| } |
| |
| assertEquals(expected, actual); |
| } |
| |
| @Test |
| public void testIncompatibleImprovementsVersionOutOfBounds() throws Exception { |
| try { |
| DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(new Version(2, 2, 0)); |
| fail(); |
| } catch (IllegalArgumentException e) { |
| // expected |
| } |
| |
| Version curVersion = Configuration.getVersion(); |
| final Version futureVersion = new Version(curVersion.getMajor(), curVersion.getMicro(), |
| curVersion.getMicro() + 1); |
| try { |
| DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(futureVersion); |
| fail(); |
| } catch (IllegalArgumentException e) { |
| // expected |
| } |
| try { |
| new DefaultObjectWrapperBuilder(futureVersion); |
| fail(); |
| } catch (IllegalArgumentException e) { |
| // expected |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testBuilder() throws Exception { |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_19); |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertTrue(bw.isClassIntrospectionCacheRestricted()); |
| |
| assertFalse(bw.getUseAdaptersForContainers()); |
| assertTrue(bw.getForceLegacyNonListCollections()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertTrue(bw.wrap(new ArrayList()) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new String[] {}) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new HashSet()) instanceof SimpleSequence); |
| |
| } |
| |
| for (boolean simpleMapWrapper : new boolean[] { true, false }) { |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21); |
| builder.setSimpleMapWrapper(simpleMapWrapper); // Shouldn't mater |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_21, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertEquals(simpleMapWrapper, bw.isSimpleMapWrapper()); |
| assertFalse(bw.getUseAdaptersForContainers()); |
| assertTrue(bw.getForceLegacyNonListCollections()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertTrue(bw.wrap(new ArrayList()) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new String[] {}) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new HashSet()) instanceof SimpleSequence); |
| assertTrue(bw.wrap('c') instanceof TemplateScalarModel); // StringModel now, but should change later |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_22); |
| builder.setSimpleMapWrapper(simpleMapWrapper); // Shouldn't mater |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_22, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertEquals(simpleMapWrapper, bw.isSimpleMapWrapper()); |
| assertTrue(bw.getUseAdaptersForContainers()); |
| assertTrue(bw.getForceLegacyNonListCollections()); |
| assertTrue(bw.wrap(new HashMap()) instanceof DefaultMapAdapter); |
| assertTrue(bw.wrap(new ArrayList()) instanceof DefaultListAdapter); |
| assertTrue(bw.wrap(new String[] {}) instanceof DefaultArrayAdapter); |
| assertTrue(bw.wrap(new HashSet()) instanceof SimpleSequence); |
| } |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.getVersion()); |
| builder.setSimpleMapWrapper(true); |
| BeansWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals( |
| DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(Configuration.getVersion()), |
| bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertTrue(bw.isSimpleMapWrapper()); |
| assertTrue(bw.wrap(new HashMap()) instanceof DefaultMapAdapter); |
| } |
| |
| { |
| DefaultObjectWrapper bw = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_19).build(); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertFalse(bw.isSimpleMapWrapper()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| |
| assertSame(bw, new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_20).build()); |
| assertSame(bw, new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_0).build()); |
| assertSame(bw, new DefaultObjectWrapperBuilder(new Version(2, 3, 5)).build()); |
| } |
| |
| { |
| DefaultObjectWrapper bw = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build(); |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_21, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertFalse(bw.isSimpleMapWrapper()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertTrue(bw.isClassIntrospectionCacheRestricted()); |
| |
| assertSame(bw, new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build()); |
| } |
| |
| { |
| DefaultObjectWrapper bw = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_19).build(); |
| assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements()); |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_19); |
| builder.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); |
| DefaultObjectWrapper bw = builder.build(); |
| DefaultObjectWrapper bw2 = builder.build(); |
| assertSame(bw, bw2); // not cached |
| |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertFalse(bw.isSimpleMapWrapper()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertEquals(BeansWrapper.EXPOSE_PROPERTIES_ONLY, bw.getExposureLevel()); |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_19); |
| builder.setExposeFields(true); |
| BeansWrapper bw = builder.build(); |
| BeansWrapper bw2 = builder.build(); |
| assertSame(bw, bw2); // not cached |
| |
| assertSame(bw.getClass(), DefaultObjectWrapper.class); |
| assertEquals(Configuration.VERSION_2_3_0, bw.getIncompatibleImprovements()); |
| assertTrue(bw.isWriteProtected()); |
| assertFalse(bw.isSimpleMapWrapper()); |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertEquals(true, bw.isExposeFields()); |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21); |
| builder.setForceLegacyNonListCollections(false); |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertFalse(bw.getForceLegacyNonListCollections()); |
| |
| assertTrue(bw.wrap(new HashMap()) instanceof SimpleHash); |
| assertTrue(bw.wrap(new ArrayList()) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new String[] {}) instanceof SimpleSequence); |
| assertTrue(bw.wrap(new HashSet()) instanceof SimpleSequence); |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_22); |
| builder.setForceLegacyNonListCollections(false); |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertFalse(bw.getForceLegacyNonListCollections()); |
| |
| assertTrue(bw.wrap(new HashMap()) instanceof DefaultMapAdapter); |
| assertTrue(bw.wrap(new ArrayList()) instanceof DefaultListAdapter); |
| assertTrue(bw.wrap(new String[] {}) instanceof DefaultArrayAdapter); |
| assertTrue(bw.wrap(new HashSet()) instanceof DefaultNonListCollectionAdapter); |
| } |
| |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.getVersion()); |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertFalse(bw.getIterableSupport()); |
| |
| assertFalse(bw.wrap(new PureIterable()) instanceof DefaultIterableAdapter); |
| } |
| { |
| DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.getVersion()); |
| builder.setIterableSupport(true); |
| DefaultObjectWrapper bw = builder.build(); |
| assertSame(bw, builder.build()); |
| assertTrue(bw.getIterableSupport()); |
| |
| assertTrue(bw.wrap(new PureIterable()) instanceof DefaultIterableAdapter); |
| } |
| } |
| |
| @Test |
| public void testConstructors() throws Exception { |
| { |
| DefaultObjectWrapper ow = new DefaultObjectWrapper(); |
| assertEquals(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS, ow.getIncompatibleImprovements()); |
| assertFalse(ow.isWriteProtected()); |
| assertFalse(ow.getUseAdaptersForContainers()); |
| assertTrue(ow.getForceLegacyNonListCollections()); |
| } |
| |
| { |
| DefaultObjectWrapper ow = new DefaultObjectWrapper(Configuration.VERSION_2_3_20); |
| assertEquals(Configuration.VERSION_2_3_0, ow.getIncompatibleImprovements()); |
| assertFalse(ow.isWriteProtected()); |
| assertFalse(ow.getUseAdaptersForContainers()); |
| assertTrue(ow.getForceLegacyNonListCollections()); |
| } |
| |
| { |
| DefaultObjectWrapper ow = new DefaultObjectWrapper(Configuration.VERSION_2_3_21); |
| assertEquals(Configuration.VERSION_2_3_21, ow.getIncompatibleImprovements()); |
| assertFalse(ow.isWriteProtected()); |
| assertFalse(ow.getUseAdaptersForContainers()); |
| assertTrue(ow.getForceLegacyNonListCollections()); |
| } |
| |
| { |
| DefaultObjectWrapper ow = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| assertEquals(Configuration.VERSION_2_3_22, ow.getIncompatibleImprovements()); |
| assertFalse(ow.isWriteProtected()); |
| assertTrue(ow.getUseAdaptersForContainers()); |
| assertTrue(ow.getForceLegacyNonListCollections()); |
| } |
| |
| try { |
| new DefaultObjectWrapper(new Version(99, 9, 9)); |
| fail(); |
| } catch (IllegalArgumentException e) { |
| assertThat(e.getMessage(), containsString("version")); |
| } |
| } |
| |
| |
| @Test |
| public void testCustomization() throws TemplateModelException { |
| { |
| CustomizedDefaultObjectWrapper ow = new CustomizedDefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| assertEquals(Configuration.VERSION_2_3_22, ow.getIncompatibleImprovements()); |
| assertTrue(ow.getUseAdaptersForContainers()); |
| testCustomizationCommonPart(ow, |
| DefaultMapAdapter.class, DefaultListAdapter.class, DefaultArrayAdapter.class); |
| } |
| |
| { |
| CustomizedDefaultObjectWrapper ow = new CustomizedDefaultObjectWrapper(Configuration.VERSION_2_3_21); |
| assertFalse(ow.getUseAdaptersForContainers()); |
| assertEquals(Configuration.VERSION_2_3_21, ow.getIncompatibleImprovements()); |
| testCustomizationCommonPart(ow, |
| SimpleHash.class, SimpleSequence.class, SimpleSequence.class); |
| } |
| |
| { |
| CustomizedDefaultObjectWrapper ow = new CustomizedDefaultObjectWrapper(Configuration.VERSION_2_3_20); |
| assertFalse(ow.getUseAdaptersForContainers()); |
| assertEquals(Configuration.VERSION_2_3_0, ow.getIncompatibleImprovements()); |
| testCustomizationCommonPart(ow, |
| SimpleHash.class, SimpleSequence.class, SimpleSequence.class); |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| private void testCustomizationCommonPart(CustomizedDefaultObjectWrapper ow, |
| Class<? extends TemplateHashModel> mapTMClass, |
| Class<? extends TemplateSequenceModel> listTMClass, |
| Class<? extends TemplateSequenceModel> arrayTMClass) |
| throws TemplateModelException { |
| assertFalse(ow.isWriteProtected()); |
| |
| TemplateSequenceModel seq = (TemplateSequenceModel) ow.wrap(new Tupple(11, 22)); |
| assertEquals(2, seq.size()); |
| assertEquals(11, ow.unwrap(seq.get(0))); |
| assertEquals(22, ow.unwrap(seq.get(1))); |
| |
| assertTrue(ow.wrap("x") instanceof SimpleScalar); |
| assertTrue(ow.wrap(1.5) instanceof SimpleNumber); |
| assertTrue(ow.wrap(new Date()) instanceof SimpleDate); |
| assertEquals(TemplateBooleanModel.TRUE, ow.wrap(true)); |
| |
| assertTrue(mapTMClass.isInstance(ow.wrap(Collections.emptyMap()))); |
| assertTrue(listTMClass.isInstance(ow.wrap(Collections.emptyList()))); |
| assertTrue(arrayTMClass.isInstance(ow.wrap(new boolean[] { }))); |
| assertTrue(ow.wrap(new HashSet()) instanceof SimpleSequence); // at least until IcI 2.4 |
| assertTrue(ow.wrap('c') instanceof TemplateScalarModel); // StringModel right now, but should change later |
| |
| TemplateHashModel bean = (TemplateHashModel) ow.wrap(new TestBean()); |
| assertEquals(1, ow.unwrap(bean.get("x"))); |
| { |
| // Check method calls, and also if the return value is wrapped with the overidden "wrap". |
| final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("m")).exec(Collections.emptyList()); |
| assertEquals( |
| Collections.singletonList(1), |
| ow.unwrap(mr)); |
| assertTrue(listTMClass.isInstance(mr)); |
| } |
| { |
| // Check custom TM usage and round trip: |
| final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("incTupple")) |
| .exec(Collections.singletonList(ow.wrap(new Tupple<Integer, Integer>(1, 2)))); |
| assertEquals(new Tupple<Integer, Integer>(2, 3), ow.unwrap(mr)); |
| assertTrue(TuppleAdapter.class.isInstance(mr)); |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testRoundtripping() throws TemplateModelException, ClassNotFoundException { |
| DefaultObjectWrapper dow21 = new DefaultObjectWrapper(Configuration.VERSION_2_3_21); |
| DefaultObjectWrapper dow22 = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| |
| final Map hashMap = new HashMap(); |
| inintTestMap(hashMap); |
| final Map treeMap = new TreeMap(); |
| inintTestMap(treeMap); |
| final Map linkedHashMap = new LinkedHashMap(); |
| inintTestMap(linkedHashMap); |
| final Map gMap = ImmutableMap.<String, Object> of("a", 1, "b", 2, "c", 3); |
| final LinkedList linkedList = new LinkedList(); |
| linkedList.add("a"); |
| linkedList.add("b"); |
| linkedList.add("c"); |
| final int[] intArray = new int[] { 1, 2, 3 }; |
| final String[] stringArray = new String[] { "a", "b", "c" }; |
| |
| assertRoundtrip(dow21, linkedHashMap, SimpleHash.class, HashAdapter.class, linkedHashMap.toString()); |
| assertRoundtrip(dow21, treeMap, SimpleHash.class, HashAdapter.class, treeMap.toString()); |
| assertRoundtrip(dow21, gMap, SimpleHash.class, HashAdapter.class, hashMap.toString()); |
| assertRoundtrip(dow21, linkedList, SimpleSequence.class, Class.forName("freemarker.ext.beans.SequenceAdapter"), |
| linkedList.toString()); |
| assertRoundtrip(dow21, intArray, SimpleSequence.class, Class.forName("freemarker.ext.beans.SequenceAdapter"), |
| "[1, 2, 3]"); |
| assertRoundtrip(dow21, stringArray, SimpleSequence.class, |
| Class.forName("freemarker.ext.beans.SequenceAdapter"), |
| "[a, b, c]"); |
| |
| assertRoundtrip(dow22, linkedHashMap, DefaultMapAdapter.class, LinkedHashMap.class, linkedHashMap.toString()); |
| assertRoundtrip(dow22, treeMap, DefaultMapAdapter.class, TreeMap.class, treeMap.toString()); |
| assertRoundtrip(dow22, gMap, DefaultMapAdapter.class, ImmutableMap.class, gMap.toString()); |
| assertRoundtrip(dow22, linkedList, DefaultListAdapter.class, LinkedList.class, linkedList.toString()); |
| assertRoundtrip(dow22, intArray, DefaultArrayAdapter.class, int[].class, null); |
| assertRoundtrip(dow22, stringArray, DefaultArrayAdapter.class, String[].class, null); |
| } |
| |
| @SuppressWarnings("boxing") |
| private void inintTestMap(Map map) { |
| map.put("a", 1); |
| map.put("b", 2); |
| map.put("c", 3); |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testMapAdapter() throws TemplateModelException { |
| HashMap<String, Object> testMap = new LinkedHashMap<String, Object>(); |
| testMap.put("a", 1); |
| testMap.put("b", null); |
| testMap.put("c", "C"); |
| testMap.put("d", Collections.singletonList("x")); |
| |
| { |
| TemplateHashModelEx hash = (TemplateHashModelEx) OW22.wrap(testMap); |
| assertEquals(4, hash.size()); |
| assertFalse(hash.isEmpty()); |
| assertNull(hash.get("e")); |
| assertEquals(1, ((TemplateNumberModel) hash.get("a")).getAsNumber()); |
| assertNull(hash.get("b")); |
| assertEquals("C", ((TemplateScalarModel) hash.get("c")).getAsString()); |
| assertTrue(hash.get("d") instanceof DefaultListAdapter); |
| |
| assertCollectionTMEquals(hash.keys(), "a", "b", "c", "d"); |
| assertCollectionTMEquals(hash.values(), 1, null, "C", Collections.singletonList("x")); |
| |
| assertSizeThroughAPIModel(4, hash); |
| } |
| |
| { |
| assertTrue(((TemplateHashModel) OW22.wrap(Collections.emptyMap())).isEmpty()); |
| } |
| |
| { |
| final TemplateHashModelEx hash = (TemplateHashModelEx) OW22NM.wrap(testMap); |
| assertSame(NullModel.INSTANCE, hash.get("b")); |
| assertNull(hash.get("e")); |
| |
| assertCollectionTMEquals(hash.keys(), "a", "b", "c", "d"); |
| assertCollectionTMEquals(hash.values(), 1, null, "C", Collections.singletonList("x")); |
| } |
| } |
| |
| private void assertCollectionTMEquals(TemplateCollectionModel coll, Object... expectedItems) |
| throws TemplateModelException { |
| for (int i = 0; i < 2; i++) { // Run twice to check if we always get a new iterator |
| int idx = 0; |
| TemplateModelIterator it2 = null; |
| for (TemplateModelIterator it = coll.iterator(); it.hasNext(); ) { |
| TemplateModel actualItem = it.next(); |
| if (idx >= expectedItems.length) { |
| fail("Number of items is more than the expected " + expectedItems.length); |
| } |
| assertEquals(expectedItems[idx], OW22.unwrap(actualItem)); |
| if (i == 1) { |
| // In the 2nd round we also test with two iterators in parallel. |
| // This 2nd iterator is also special in that its hasNext() is never called. |
| if (it2 == null) { |
| it2 = coll.iterator(); |
| } |
| assertEquals(expectedItems[idx], OW22.unwrap(it2.next())); |
| } |
| idx++; |
| } |
| if (expectedItems.length != idx) { |
| fail("Number of items is " + idx + ", which is less than the expected " + expectedItems.length); |
| } |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testListAdapter() throws TemplateModelException { |
| { |
| List testList = new ArrayList<Object>(); |
| testList.add(1); |
| testList.add(null); |
| testList.add("c"); |
| testList.add(new String[] { "x" }); |
| |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testList); |
| assertTrue(seq instanceof DefaultListAdapter); |
| assertFalse(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0 |
| assertEquals(4, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber()); |
| assertNull(seq.get(1)); |
| assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString()); |
| assertTrue(seq.get(3) instanceof DefaultArrayAdapter); |
| assertNull(seq.get(4)); |
| |
| assertSizeThroughAPIModel(4, seq); |
| } |
| |
| { |
| List testList = new LinkedList<Object>(); |
| testList.add(1); |
| testList.add(null); |
| testList.add("c"); |
| |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testList); |
| assertTrue(seq instanceof DefaultListAdapter); |
| assertTrue(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0 |
| assertEquals(3, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber()); |
| assertNull(seq.get(1)); |
| assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString()); |
| assertNull(seq.get(3)); |
| |
| assertCollectionTMEquals((TemplateCollectionModel) seq, 1, null, "c"); |
| |
| TemplateModelIterator it = ((TemplateCollectionModel) seq).iterator(); |
| it.next(); |
| it.next(); |
| it.next(); |
| try { |
| it.next(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsString("no more")); |
| } |
| } |
| |
| { |
| List testList = new ArrayList<Object>(); |
| testList.add(null); |
| |
| final TemplateSequenceModel seq = (TemplateSequenceModel) OW22NM.wrap(testList); |
| assertSame(NullModel.INSTANCE, seq.get(0)); |
| assertNull(seq.get(1)); |
| } |
| } |
| |
| @Test |
| public void testArrayAdapterTypes() throws TemplateModelException { |
| assertArrayAdapterClass("Object", OW22.wrap(new Object[] {})); |
| assertArrayAdapterClass("Object", OW22.wrap(new String[] {})); |
| assertArrayAdapterClass("byte", OW22.wrap(new byte[] {})); |
| assertArrayAdapterClass("short", OW22.wrap(new short[] {})); |
| assertArrayAdapterClass("int", OW22.wrap(new int[] {})); |
| assertArrayAdapterClass("long", OW22.wrap(new long[] {})); |
| assertArrayAdapterClass("float", OW22.wrap(new float[] {})); |
| assertArrayAdapterClass("double", OW22.wrap(new double[] {})); |
| assertArrayAdapterClass("boolean", OW22.wrap(new boolean[] {})); |
| assertArrayAdapterClass("char", OW22.wrap(new char[] {})); |
| } |
| |
| private void assertArrayAdapterClass(String adapterCompType, TemplateModel adaptedArray) { |
| assertTrue(adaptedArray instanceof DefaultArrayAdapter); |
| assertThat(adaptedArray.getClass().getName(), |
| containsString("$" + adapterCompType.substring(0, 1).toUpperCase() + adapterCompType.substring(1))); |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testArrayAdapters() throws TemplateModelException { |
| { |
| final String[] testArray = new String[] { "a", null, "c" }; |
| |
| { |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testArray); |
| assertEquals(3, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString()); |
| assertNull(seq.get(1)); |
| assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString()); |
| assertNull(seq.get(3)); |
| } |
| |
| { |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22NM.wrap(testArray); |
| assertNull(seq.get(-1)); |
| assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString()); |
| assertSame(NullModel.INSTANCE, seq.get(1)); |
| assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString()); |
| assertNull(seq.get(3)); |
| } |
| } |
| |
| { |
| final int[] testArray = new int[] { 11, 22 }; |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testArray); |
| assertEquals(2, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEqualsAndSameClass(Integer.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber()); |
| assertEqualsAndSameClass(Integer.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber()); |
| assertNull(seq.get(2)); |
| } |
| |
| { |
| final double[] testArray = new double[] { 11, 22 }; |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testArray); |
| assertEquals(2, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEqualsAndSameClass(Double.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber()); |
| assertEqualsAndSameClass(Double.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber()); |
| assertNull(seq.get(2)); |
| } |
| |
| { |
| final boolean[] testArray = new boolean[] { true, false }; |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testArray); |
| assertEquals(2, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEqualsAndSameClass(Boolean.valueOf(true), ((TemplateBooleanModel) seq.get(0)).getAsBoolean()); |
| assertEqualsAndSameClass(Boolean.valueOf(false), ((TemplateBooleanModel) seq.get(1)).getAsBoolean()); |
| assertNull(seq.get(2)); |
| } |
| |
| { |
| final char[] testArray = new char[] { 'a', 'b' }; |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(testArray); |
| assertEquals(2, seq.size()); |
| assertNull(seq.get(-1)); |
| assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString()); |
| assertEquals("b", ((TemplateScalarModel) seq.get(1)).getAsString()); |
| assertNull(seq.get(2)); |
| } |
| } |
| |
| private void assertEqualsAndSameClass(Object expected, Object actual) { |
| assertEquals(expected, actual); |
| if (expected != null) { |
| assertEquals(expected.getClass(), actual.getClass()); |
| } |
| } |
| |
| private void assertRoundtrip(DefaultObjectWrapper dow, Object obj, Class expectedTMClass, |
| Class expectedPojoClass, |
| String expectedPojoToString) |
| throws TemplateModelException { |
| final TemplateModel objTM = dow.wrap(obj); |
| assertTrue(expectedTMClass.isAssignableFrom(objTM.getClass())); |
| |
| final TemplateHashModel testBeanTM = (TemplateHashModel) dow.wrap(new RoundtripTesterBean()); |
| |
| { |
| TemplateMethodModelEx getClassM = (TemplateMethodModelEx) testBeanTM.get("getClass"); |
| Object r = getClassM.exec(Collections.singletonList(objTM)); |
| final Class rClass = (Class) ((WrapperTemplateModel) r).getWrappedObject(); |
| assertTrue(rClass + " instanceof " + expectedPojoClass, expectedPojoClass.isAssignableFrom(rClass)); |
| } |
| |
| if (expectedPojoToString != null) { |
| TemplateMethodModelEx getToStringM = (TemplateMethodModelEx) testBeanTM.get("toString"); |
| Object r = getToStringM.exec(Collections.singletonList(objTM)); |
| assertEquals(expectedPojoToString, ((TemplateScalarModel) r).getAsString()); |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testCollectionAdapterBasics() throws TemplateModelException { |
| { |
| Set set = new TreeSet(); |
| set.add("a"); |
| set.add("b"); |
| set.add("c"); |
| TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW22CA.wrap(set); |
| assertTrue(coll instanceof DefaultNonListCollectionAdapter); |
| assertEquals(3, coll.size()); |
| assertFalse(coll.isEmpty()); |
| assertCollectionTMEquals(coll, "a", "b", "c"); |
| |
| assertRoundtrip(OW22CA, set, DefaultNonListCollectionAdapter.class, TreeSet.class, "[a, b, c]"); |
| |
| assertSizeThroughAPIModel(3, coll); |
| } |
| |
| { |
| Set set = new HashSet(); |
| final List<String> list = Collections.singletonList("b"); |
| set.add(list); |
| set.add(null); |
| TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW22CA.wrap(set); |
| TemplateModelIterator it = coll.iterator(); |
| final TemplateModel tm1 = it.next(); |
| Object obj1 = OW22CA.unwrap(tm1); |
| final TemplateModel tm2 = it.next(); |
| Object obj2 = OW22CA.unwrap(tm2); |
| assertTrue(obj1 == null || obj2 == null); |
| assertTrue(obj1 != null && obj1.equals(list) || obj2 != null && obj2.equals(list)); |
| assertTrue(tm1 instanceof DefaultListAdapter || tm2 instanceof DefaultListAdapter); |
| |
| assertRoundtrip(OW22CA, set, DefaultNonListCollectionAdapter.class, HashSet.class, "[" + obj1 + ", " |
| + obj2 + "]"); |
| } |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testCollectionAdapterOutOfBounds() throws TemplateModelException { |
| Set set = Collections.singleton(123); |
| |
| TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW22CA.wrap(set); |
| TemplateModelIterator it = coll.iterator(); |
| |
| for (int i = 0; i < 3; i++) { |
| assertTrue(it.hasNext()); |
| } |
| |
| assertEquals(123, OW22CA.unwrap(it.next())); |
| |
| for (int i = 0; i < 3; i++) { |
| assertFalse(it.hasNext()); |
| try { |
| it.next(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("no more")); |
| } |
| } |
| } |
| |
| @Test |
| public void testCollectionAdapterAndNulls() throws TemplateModelException { |
| Set set = new HashSet(); |
| set.add(null); |
| |
| { |
| DefaultObjectWrapper dow = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| dow.setForceLegacyNonListCollections(false); |
| TemplateCollectionModelEx coll = (TemplateCollectionModelEx) dow.wrap(set); |
| assertEquals(1, coll.size()); |
| assertFalse(coll.isEmpty()); |
| assertNull(coll.iterator().next()); |
| } |
| |
| { |
| DefaultObjectWrapper dow = new DefaultObjectWrapper(Configuration.VERSION_2_3_22); |
| dow.setForceLegacyNonListCollections(false); |
| dow.setNullModel(NullModel.INSTANCE); |
| TemplateCollectionModelEx coll = (TemplateCollectionModelEx) dow.wrap(set); |
| assertEquals(1, coll.size()); |
| assertFalse(coll.isEmpty()); |
| assertEquals(NullModel.INSTANCE, coll.iterator().next()); |
| } |
| } |
| |
| @Test |
| public void testLegacyNonListCollectionWrapping() throws TemplateModelException { |
| Set set = new TreeSet(); |
| set.add("a"); |
| set.add("b"); |
| set.add("c"); |
| TemplateSequenceModel seq = (TemplateSequenceModel) OW22.wrap(set); |
| assertTrue(seq instanceof SimpleSequence); |
| assertEquals(3, seq.size()); |
| assertEquals("a", OW22.unwrap(seq.get(0))); |
| assertEquals("b", OW22.unwrap(seq.get(1))); |
| assertEquals("c", OW22.unwrap(seq.get(2))); |
| } |
| |
| @Test |
| public void testIteratorWrapping() throws TemplateModelException, ClassNotFoundException { |
| testIteratorWrapping(OW0, SimpleCollection.class, Class.forName("freemarker.ext.beans.SetAdapter")); |
| testIteratorWrapping(OW22, DefaultIteratorAdapter.class, Iterator.class); |
| } |
| |
| private void testIteratorWrapping(DefaultObjectWrapper ow, Class<?> expectedTMClass, Class<?> expectedPOJOClass) |
| throws TemplateModelException { |
| final List<String> list = ImmutableList.<String> of("a", "b", "c"); |
| Iterator<String> it = list.iterator(); |
| TemplateCollectionModel coll = (TemplateCollectionModel) ow.wrap(it); |
| |
| assertRoundtrip(ow, coll, expectedTMClass, expectedPOJOClass, null); |
| |
| TemplateModelIterator itIt = coll.iterator(); |
| TemplateModelIterator itIt2 = coll.iterator(); // used later |
| assertTrue(itIt.hasNext()); |
| assertEquals("a", ow.unwrap(itIt.next())); |
| assertTrue(itIt.hasNext()); |
| assertEquals("b", ow.unwrap(itIt.next())); |
| assertTrue(itIt.hasNext()); |
| assertEquals("c", ow.unwrap(itIt.next())); |
| assertFalse(itIt.hasNext()); |
| try { |
| itIt.next(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("no more")); |
| } |
| |
| try { |
| itIt2.hasNext(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsString("can be listed only once")); |
| } |
| |
| TemplateModelIterator itIt3 = coll.iterator(); |
| try { |
| itIt3.hasNext(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsString("can be listed only once")); |
| } |
| } |
| |
| @Test |
| public void testIteratorApiSupport() throws TemplateModelException { |
| TemplateModel wrappedIterator = OW22.wrap(Collections.emptyIterator()); |
| assertThat(wrappedIterator, instanceOf(DefaultIteratorAdapter.class)); |
| DefaultIteratorAdapter iteratorAdapter = (DefaultIteratorAdapter) wrappedIterator; |
| |
| TemplateHashModel api = (TemplateHashModel) iteratorAdapter.getAPI(); |
| assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx) |
| api.get("hasNext")).exec(Collections.emptyList())).getAsBoolean()); |
| } |
| |
| @SuppressWarnings("boxing") |
| @Test |
| public void testCharKeyFallback() throws TemplateModelException { |
| Map hashMapS = new HashMap<String, Integer>(); |
| hashMapS.put("a", 1); |
| Map sortedMapS = new TreeMap<String, Integer>(); |
| sortedMapS.put("a", 1); |
| Map hashMapC = new HashMap<Character, Integer>(); |
| hashMapC.put('a', 1); |
| Map sortedMapC = new TreeMap<Character, Integer>(); |
| sortedMapC.put('a', 1); |
| |
| for (DefaultObjectWrapper ow : new DefaultObjectWrapper[] { OW0, OW22 } ) { |
| assertEquals(1, ow.unwrap(((TemplateHashModel) ow.wrap(hashMapS)).get("a"))); |
| assertEquals(1, ow.unwrap(((TemplateHashModel) ow.wrap(hashMapC)).get("a"))); |
| assertEquals(1, ow.unwrap(((TemplateHashModel) ow.wrap(sortedMapS)).get("a"))); |
| try { |
| ((TemplateHashModel) ow.wrap(sortedMapC)).get("a"); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("String key")); |
| } |
| |
| assertNull(((TemplateHashModel) ow.wrap(hashMapS)).get("b")); |
| assertNull(((TemplateHashModel) ow.wrap(hashMapC)).get("b")); |
| assertNull(((TemplateHashModel) ow.wrap(sortedMapS)).get("b")); |
| try { |
| ((TemplateHashModel) ow.wrap(sortedMapC)).get("b"); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("String key")); |
| } |
| } |
| } |
| |
| @Test |
| public void testIterableSupport() throws TemplateException, IOException { |
| Iterable<String> iterable = new PureIterable(); |
| |
| String listingFTL = "<#list value as x>${x}<#sep>, </#list>"; |
| |
| { |
| DefaultObjectWrapper ow = OW22; |
| TemplateModel tm = ow.wrap(iterable); |
| assertThat(tm, instanceOf(TemplateHashModel.class)); |
| assertThat(tm, not(instanceOf(TemplateCollectionModel.class))); |
| assertThat(tm, not(instanceOf(TemplateSequenceModel.class))); |
| assertNotNull(((TemplateHashModel) tm).get("iterator")); |
| |
| assertTemplateFails(ow, iterable, listingFTL, "iterableSupport"); |
| } |
| |
| { |
| DefaultObjectWrapper ow = OW22IS; |
| TemplateModel tm = ow.wrap(iterable); |
| assertThat(tm, instanceOf(TemplateCollectionModel.class)); |
| TemplateCollectionModel iterableTM = (TemplateCollectionModel) tm; |
| |
| for (int i = 0; i < 2; i++) { |
| TemplateModelIterator iteratorTM = iterableTM.iterator(); |
| assertTrue(iteratorTM.hasNext()); |
| assertEquals("a", ow.unwrap(iteratorTM.next())); |
| assertTrue(iteratorTM.hasNext()); |
| assertEquals("b", ow.unwrap(iteratorTM.next())); |
| assertTrue(iteratorTM.hasNext()); |
| assertEquals("c", ow.unwrap(iteratorTM.next())); |
| assertFalse(iteratorTM.hasNext()); |
| try { |
| iteratorTM.next(); |
| fail(); |
| } catch (TemplateModelException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("no more")); |
| } |
| } |
| |
| assertTemplateOutput(OW22IS, iterable, listingFTL, "a, b, c"); |
| } |
| } |
| |
| @Test |
| public void testNoEnumerationAdapter() throws TemplateModelException { |
| DefaultObjectWrapper ow = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25).build(); |
| Vector<String> vector = new Vector<String>(); |
| vector.add("a"); |
| vector.add("b"); |
| |
| TemplateModel wrappedEnumeration = ow.wrap(vector.elements()); |
| assertThat(wrappedEnumeration, instanceOf(EnumerationModel.class)); |
| EnumerationModel enumModel = (EnumerationModel) wrappedEnumeration; |
| assertNotNull(enumModel.get("nextElement")); |
| } |
| |
| @Test |
| public void testEnumerationAdapter() throws TemplateModelException { |
| DefaultObjectWrapper ow = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_26).build(); |
| Vector<String> vector = new Vector<String>(); |
| vector.add("a"); |
| vector.add("b"); |
| |
| TemplateModel wrappedEnumeration = ow.wrap(vector.elements()); |
| assertThat(wrappedEnumeration, instanceOf(DefaultEnumerationAdapter.class)); |
| DefaultEnumerationAdapter enumAdapter = (DefaultEnumerationAdapter) wrappedEnumeration; |
| TemplateModelIterator iterator = enumAdapter.iterator(); |
| assertTrue(iterator.hasNext()); |
| assertEquals("a", ((TemplateScalarModel) iterator.next()).getAsString()); |
| assertTrue(iterator.hasNext()); |
| assertEquals("b", ((TemplateScalarModel) iterator.next()).getAsString()); |
| assertFalse(iterator.hasNext()); |
| |
| iterator = enumAdapter.iterator(); |
| try { |
| iterator.hasNext(); |
| } catch (TemplateException e) { |
| assertThat(e.getMessage(), containsStringIgnoringCase("only once")); |
| } |
| |
| TemplateHashModel api = (TemplateHashModel) enumAdapter.getAPI(); |
| assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx) |
| api.get("hasMoreElements")).exec(Collections.emptyList())).getAsBoolean()); |
| } |
| |
| @Test |
| public void testCanWrapDOM() throws SAXException, IOException, ParserConfigurationException, |
| TemplateModelException { |
| DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| InputSource is = new InputSource(); |
| is.setCharacterStream(new StringReader("<doc><sub a='1' /></doc>")); |
| Document doc = db.parse(is); |
| assertTrue(OW22.wrap(doc) instanceof TemplateNodeModel); |
| } |
| |
| @Test |
| public void testPreferIndexedReadMethodAndIcI() { |
| assertTrue(new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_26).build().getPreferIndexedReadMethod()); |
| assertTrue(new DefaultObjectWrapper(Configuration.VERSION_2_3_26).getPreferIndexedReadMethod()); |
| |
| assertFalse(new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27).build().getPreferIndexedReadMethod()); |
| assertFalse(new DefaultObjectWrapper(Configuration.VERSION_2_3_27).getPreferIndexedReadMethod()); |
| } |
| |
| private void assertSizeThroughAPIModel(int expectedSize, TemplateModel normalModel) throws TemplateModelException { |
| if (!(normalModel instanceof TemplateModelWithAPISupport)) { |
| fail(); |
| } |
| TemplateHashModel apiModel = (TemplateHashModel) ((TemplateModelWithAPISupport) normalModel).getAPI(); |
| TemplateMethodModelEx sizeMethod = (TemplateMethodModelEx) apiModel.get("size"); |
| TemplateNumberModel r = (TemplateNumberModel) sizeMethod.exec(Collections.emptyList()); |
| assertEquals(expectedSize, r.getAsNumber().intValue()); |
| } |
| |
| private void assertTemplateOutput(ObjectWrapper objectWrapper, Object value, String ftl, String expectedOutput) |
| throws TemplateException, IOException { |
| assertEquals(expectedOutput, processTemplate(objectWrapper, value, ftl)); |
| } |
| |
| private void assertTemplateFails(ObjectWrapper objectWrapper, Object value, String ftl, String expectedMessagePart) |
| throws TemplateException, IOException { |
| try { |
| processTemplate(objectWrapper, value, ftl); |
| fail(); |
| } catch (TemplateException e) { |
| assertThat(e.getMessage(), containsString(expectedMessagePart)); |
| } |
| } |
| |
| private String processTemplate(ObjectWrapper objectWrapper, Object value, String ftl) |
| throws TemplateException, IOException { |
| Configuration cfg = new Configuration(Configuration.VERSION_2_3_24); |
| cfg.setLogTemplateExceptions(false); |
| cfg.setObjectWrapper(objectWrapper); |
| StringWriter out = new StringWriter(); |
| new Template(null, ftl, cfg).process(ImmutableMap.of("value", value), out); |
| return out.toString(); |
| } |
| |
| private static final class PureIterable implements Iterable<String> { |
| public Iterator<String> iterator() { |
| return ImmutableList.of("a", "b", "c").iterator(); |
| } |
| } |
| |
| public static class RoundtripTesterBean { |
| |
| public Class getClass(Object o) { |
| return o.getClass(); |
| } |
| |
| public String toString(Object o) { |
| return o.toString(); |
| } |
| |
| } |
| |
| private static final class NullModel implements TemplateModel, AdapterTemplateModel { |
| |
| final static NullModel INSTANCE = new NullModel(); |
| |
| public Object getAdaptedObject(Class hint) { |
| return null; |
| } |
| |
| } |
| |
| private static class Tupple<E1, E2> { |
| |
| private final E1 e1; |
| private final E2 e2; |
| |
| public Tupple(E1 e1, E2 e2) { |
| if (e1 == null || e2 == null) throw new NullPointerException(); |
| this.e1 = e1; |
| this.e2 = e2; |
| } |
| |
| public E1 getE1() { |
| return e1; |
| } |
| |
| public E2 getE2() { |
| return e2; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((e1 == null) ? 0 : e1.hashCode()); |
| result = prime * result + ((e2 == null) ? 0 : e2.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) return true; |
| if (obj == null) return false; |
| if (getClass() != obj.getClass()) return false; |
| Tupple other = (Tupple) obj; |
| if (e1 == null) { |
| if (other.e1 != null) return false; |
| } else if (!e1.equals(other.e1)) return false; |
| if (e2 == null) { |
| if (other.e2 != null) return false; |
| } else if (!e2.equals(other.e2)) return false; |
| return true; |
| } |
| |
| } |
| |
| @SuppressWarnings("boxing") |
| public static class TestBean { |
| |
| public int getX() { |
| return 1; |
| } |
| |
| public List<Integer> m() { |
| return Collections.singletonList(1); |
| } |
| |
| public Tupple incTupple(Tupple<Integer, Integer> tupple) { |
| return new Tupple(tupple.e1 + 1, tupple.e2 + 1); |
| } |
| |
| } |
| |
| private static class CustomizedDefaultObjectWrapper extends DefaultObjectWrapper { |
| |
| private CustomizedDefaultObjectWrapper(Version incompatibleImprovements) { |
| super(incompatibleImprovements); |
| } |
| |
| @Override |
| protected TemplateModel handleUnknownType(final Object obj) throws TemplateModelException { |
| if (obj instanceof Tupple) { |
| return new TuppleAdapter((Tupple<?, ?>) obj, this); |
| } |
| |
| return super.handleUnknownType(obj); |
| } |
| |
| } |
| |
| private static class TuppleAdapter extends WrappingTemplateModel implements TemplateSequenceModel, |
| AdapterTemplateModel { |
| |
| private final Tupple<?, ?> tupple; |
| |
| public TuppleAdapter(Tupple<?, ?> tupple, ObjectWrapper ow) { |
| super(ow); |
| this.tupple = tupple; |
| } |
| |
| public int size() throws TemplateModelException { |
| return 2; |
| } |
| |
| public TemplateModel get(int index) throws TemplateModelException { |
| switch (index) { |
| case 0: return wrap(tupple.getE1()); |
| case 1: return wrap(tupple.getE2()); |
| default: return null; |
| } |
| } |
| |
| public Object getAdaptedObject(Class hint) { |
| return tupple; |
| } |
| |
| }; |
| |
| } |