http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
new file mode 100644
index 0000000..2c22dc6
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.model.impl;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.freemarker.core.util._NumberUtil;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("boxing")
+public class ParameterListPreferabilityTest extends TestCase {
+
+    public ParameterListPreferabilityTest(String name) {
+        super(name);
+    }
+    
+    public void testNumberical() {
+        // Note: the signature lists consists of the same elements, only their 
order changes depending on the type
+        // of the argument value.
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { (byte) 1 });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { BigDecimal.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new OverloadedNumberUtil.IntegerBigDecimal(new 
BigDecimal("1")) });
+
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { BigDecimal.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new BigDecimal("1") /* possibly non-integer */ 
});
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new OverloadedNumberUtil.FloatOrByte(1f, (byte) 
1) });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    
+                    // Two incompatibles removed, would be removed in reality:
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new OverloadedNumberUtil.IntegerOrShort(1, 
(short) 1) });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    // skip byte and short  as the would be equal with int 
(all invalid target types)
+                    new Class[] { int.class },  // In reality, this and 
Integer are removed as not-applicable overloads
+                    new Class[] { Integer.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { 1L });
+        
+        // Undecidable comparisons:
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                        new Class[] { Byte.class },
+                        new Class[] { Short.class },
+                        new Class[] { Integer.class },
+                        new Class[] { Long.class },
+                        new Class[] { BigInteger.class },
+                        new Class[] { Float.class },
+                    },
+                    new Object[] { 1.0 });
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                        new Class[] { byte.class },
+                        new Class[] { short.class },
+                        new Class[] { int.class },
+                        new Class[] { long.class },
+                        new Class[] { float.class },
+                    },
+                    new Object[] { 1.0 });
+    }
+    
+    public void testPrimitiveIsMoreSpecific() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { boolean.class },
+                    new Class[] { Boolean.class }
+                },
+                new Object[] { true });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class }
+                },
+                new Object[] { 'x' });
+    }
+    
+    public void testCharIsMoreSpecificThanString() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                    new Class[] { String.class },
+                    new Class[] { CharSequence.class }
+                },
+                new Object[] { "s" });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                    new Class[] { String.class }
+                },
+                new Object[] { 'c' });
+    }
+    
+    public void testClassHierarchy() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { LinkedHashMap.class },
+                    new Class[] { HashMap.class },
+                    new Class[] { Map.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new LinkedHashMap() });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { LinkedHashMap.class },
+                    new Class[] { Cloneable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new LinkedHashMap() });
+    }
+
+    public void testNumericalWithNonNumerical() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { Comparable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { 1 });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                },
+                new Object[] { 1 });
+    }
+    
+    public void testUnrelated() {
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                    new Class[] { Serializable.class },
+                    new Class[] { CharSequence.class },
+                    new Class[] { Comparable.class }
+                },
+                new Object[] { "s" });
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                    new Class[] { HashMap.class },
+                    new Class[] { TreeMap.class }
+                },
+                new Object[] { null });
+    }
+
+    public void testMultiParameter() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String.class, String.class },
+                        
+                    new Class[] { String.class, String.class, Object.class },
+                    new Class[] { String.class, Object.class, String.class },
+                    new Class[] { Object.class, String.class, String.class },
+                    
+                    new Class[] { String.class, Object.class, Object.class },
+                    new Class[] { Object.class, String.class, Object.class },
+                    new Class[] { Object.class, Object.class, String.class },
+                    
+                    new Class[] { Object.class, Object.class, Object.class },
+                },
+                new Object[] { "a", "b", "c" });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String.class },
+                    new Class[] { String.class, Object.class },
+                    new Class[] { CharSequence.class, CharSequence.class },
+                    new Class[] { CharSequence.class, Object.class },
+                    new Class[] { Object.class, String.class },
+                    new Class[] { Object.class, CharSequence.class },
+                    new Class[] { Object.class, Object.class },
+                },
+                new Object[] { "a", "b" });
+        
+        // Subclassing is more important than primitive-VS-boxed:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { boolean.class, boolean.class, boolean.class, 
String.class },
+                    new Class[] { Boolean.class, boolean.class, boolean.class, 
String.class },
+                    new Class[] { boolean.class, Boolean.class, Boolean.class, 
String.class },
+                    new Class[] { Boolean.class, boolean.class, Boolean.class, 
String.class },
+                    new Class[] { Boolean.class, Boolean.class, boolean.class, 
String.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, 
String.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, 
CharSequence.class },
+                    new Class[] { boolean.class, boolean.class, boolean.class, 
Object.class },
+                    new Class[] { Boolean.class, boolean.class, boolean.class, 
Object.class },
+                    new Class[] { boolean.class, Boolean.class, Boolean.class, 
Object.class },
+                    new Class[] { Boolean.class, boolean.class, Boolean.class, 
Object.class },
+                    new Class[] { Boolean.class, Boolean.class, boolean.class, 
Object.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, 
Object.class },
+                },
+                new Object[] { true, false, true, "a" });
+        
+        // Subclassing is more important than primitive-VS-boxed:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class, int.class, int.class, 
String.class },
+                    new Class[] { Integer.class, int.class, int.class, 
String.class },
+                    new Class[] { int.class, Integer.class, Integer.class, 
String.class },
+                    new Class[] { Integer.class, int.class, Integer.class, 
String.class },
+                    new Class[] { Integer.class, Integer.class, int.class, 
String.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, 
String.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, 
CharSequence.class },
+                    new Class[] { int.class, int.class, int.class, 
Object.class },
+                    new Class[] { Integer.class, int.class, int.class, 
Object.class },
+                    new Class[] { int.class, Integer.class, Integer.class, 
Object.class },
+                    new Class[] { Integer.class, int.class, Integer.class, 
Object.class },
+                    new Class[] { Integer.class, Integer.class, int.class, 
Object.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, 
Object.class },
+                },
+                new Object[] { 1, 2, 3, "a" });
+    }
+
+    public void testVarargs() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String[].class },
+                    new Class[] { String.class, CharSequence[].class },
+                    new Class[] { String.class, Object[].class },
+                },
+                new Object[] { "a", "b", "c" },
+                true);
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, int[].class },
+                    new Class[] { String.class, Integer[].class },
+                    new Class[] { String.class, long[].class },
+                    new Class[] { String.class, Long[].class },
+                    new Class[] { String.class, double[].class },
+                    new Class[] { String.class, Double[].class },
+                    new Class[] { String.class, Serializable[].class },
+                    new Class[] { String.class, Object[].class },
+                },
+                new Object[] { "a", 1, 2, 3 },
+                true);
+        
+        // 0-long varargs list; in case of ambiguity, the varargs component 
type decides:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, Object[].class },
+                    new Class[] { CharSequence.class, int[].class },
+                    new Class[] { CharSequence.class, Integer[].class },
+                    new Class[] { CharSequence.class, long[].class },
+                    new Class[] { CharSequence.class, Long[].class },
+                    new Class[] { CharSequence.class, double[].class },
+                    new Class[] { CharSequence.class, Double[].class },
+                    new Class[] { CharSequence.class, Serializable[].class },
+                    new Class[] { CharSequence.class, Object[].class },
+                    new Class[] { Object.class, int[].class },
+                },
+                new Object[] { "a" },
+                true);
+        
+        
+        // Different oms prefix length; in the case of ambiguity, the one with 
higher oms param count wins.
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, int.class, int.class, 
int[].class },
+                    new Class[] { String.class, int.class, int[].class },
+                    new Class[] { String.class, int[].class },
+                },
+                new Object[] { "a", 1, 2, 3 },
+                true);
+    }
+    
+    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, 
Object[] args) {
+        testAllCmpPermutationsInc(sortedSignatures, args, false);
+    }
+
+    /**
+     * Compares all items with all other items in the provided descending 
sorted array of signatures, checking that
+     * for all valid indexes i and j, where j > i, it stands that 
sortedSignatures[i] > sortedSignatures[j].
+     * The comparisons are done with both operand orders, also each items is 
compared to itself too.
+     * 
+     * @param sortedSignatures method signatures sorted by decreasing 
specificity
+     */
+    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, 
Object[] args, boolean varargs) {
+        final ArgumentTypes argTs = new ArgumentTypes(args);
+        for (int i = 0; i < sortedSignatures.length; i++) {
+            for (int j = 0; j < sortedSignatures.length; j++) {
+                assertEquals("sortedSignatures[" + i + "] <==> 
sortedSignatures [" + j + "]",
+                        _NumberUtil.getSignum(
+                                Integer.valueOf(j).compareTo(i)),
+                        _NumberUtil.getSignum(
+                                argTs.compareParameterListPreferability(
+                                        sortedSignatures[i], 
sortedSignatures[j], varargs)));
+            }
+        }
+    }
+
+    private void testAllCmpPermutationsEqu(Class[][] signatures, Object[] 
args) {
+        final ArgumentTypes argTs = new ArgumentTypes(args);
+        for (int i = 0; i < signatures.length; i++) {
+            for (int j = 0; j < signatures.length; j++) {
+                assertEquals("sortedSignatures[" + i + "] <==> 
sortedSignatures [" + j + "]",
+                        0,
+                        argTs.compareParameterListPreferability(signatures[i], 
signatures[j], false));
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
new file mode 100644
index 0000000..dadefba
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.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.impl;
+
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class PrallelObjectIntrospectionTest extends 
AbstractParallelIntrospectionTest {
+
+    public PrallelObjectIntrospectionTest(String name) {
+        super(name);
+    }
+
+    public static void main(String[] args) {
+        new PrallelObjectIntrospectionTest("almostForever")
+                .testReliability(Integer.MAX_VALUE);
+    }
+    
+    @Override
+    protected TemplateHashModel getWrappedEntity(int objIdx)
+    throws TemplateModelException {
+        return (TemplateHashModel) getObjectWrapper().wrap(
+                ManyObjectsOfDifferentClasses.OBJECTS[objIdx]);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
new file mode 100644
index 0000000..0cac78a
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class PrallelStaticIntrospectionTest extends 
AbstractParallelIntrospectionTest {
+
+    private static final String STATICS_CLASS_CONTAINER_CLASS_NAME
+            = ManyStaticsOfDifferentClasses.class.getName();
+
+    public PrallelStaticIntrospectionTest(String name) {
+        super(name);
+    }
+
+    public static void main(String[] args) {
+        new PrallelStaticIntrospectionTest("almostForever")
+                .testReliability(Integer.MAX_VALUE);
+    }
+    
+    @Override
+    protected TemplateHashModel getWrappedEntity(int clIdx)
+    throws TemplateModelException {
+        return (TemplateHashModel) getObjectWrapper().getStaticModels().get(
+                STATICS_CLASS_CONTAINER_CLASS_NAME + "$C"
+                + clIdx);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java 
b/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
new file mode 100644
index 0000000..7359439
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+public final class RationalNumber extends Number {
+    
+    final int divident;
+    final int divisor;
+    
+    public RationalNumber(int divident, int divisor) {
+        this.divident = divident;
+        this.divisor = divisor;
+    }
+
+    @Override
+    public int intValue() {
+        return divident / divisor;
+    }
+
+    @Override
+    public long longValue() {
+        return divident / (long) divisor;
+    }
+
+    @Override
+    public float floatValue() {
+        return (float) (divident / (double) divisor);
+    }
+
+    @Override
+    public double doubleValue() {
+        return divident / (double) divisor;
+    }
+
+    public int getDivident() {
+        return divident;
+    }
+
+    public int getDivisor() {
+        return divisor;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + divident;
+        result = prime * result + divisor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RationalNumber other = (RationalNumber) obj;
+        if (divident != other.divident)
+            return false;
+        if (divisor != other.divisor)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return divident + "/" + divisor;
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java 
b/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
new file mode 100644
index 0000000..0287d6d
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.ArrayList;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StaticModelsTest {
+
+    @Test
+    public void modelCaching() throws Exception {
+        DefaultObjectWrapper ow = new 
DefaultObjectWrapper(Configuration.VERSION_3_0_0);
+        TemplateHashModel statics = ow.getStaticModels();
+        TemplateHashModel s = (TemplateHashModel) 
statics.get(S.class.getName());
+        assertNotNull(s);
+        assertNotNull(s.get("F"));
+        assertNotNull(s.get("m"));
+        try {
+            s.get("x");
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("No such key"));
+        }
+        
+        try {
+            statics.get("no.such.ClassExists");
+            fail();
+        } catch (TemplateModelException e) {
+            assertTrue(e.getCause() instanceof ClassNotFoundException);
+        }
+        
+        TemplateModel f = s.get("F");
+        assertTrue(f instanceof TemplateScalarModel);
+        assertEquals(((TemplateScalarModel) f).getAsString(), "F OK");
+        
+        TemplateModel m = s.get("m");
+        assertTrue(m instanceof TemplateMethodModelEx);
+        assertEquals(((TemplateScalarModel) ((TemplateMethodModelEx) 
m).exec(new ArrayList())).getAsString(), "m OK");
+        
+        assertSame(s, statics.get(S.class.getName()));
+        
+        ow.clearClassIntrospecitonCache();
+        TemplateHashModel sAfterClean = (TemplateHashModel) 
statics.get(S.class.getName());
+        assertNotSame(s, sAfterClean);
+        assertSame(sAfterClean, statics.get(S.class.getName()));
+        assertNotNull(sAfterClean.get("F"));
+        assertNotNull(sAfterClean.get("m"));
+    }
+    
+    public static class S {
+        
+        public static final String F = "F OK"; 
+        
+        public static String m() {
+            return "m OK";
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java 
b/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
new file mode 100644
index 0000000..856a69f
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
@@ -0,0 +1,671 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.model.impl;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.Configuration;
+
+import junit.framework.TestCase;
+
+public class TypeFlagsTest extends TestCase {
+
+    public TypeFlagsTest(String name) {
+        super(name);
+    }
+    
+    private final DefaultObjectWrapper ow = new 
DefaultObjectWrapper(Configuration.VERSION_3_0_0);
+
+    public void testSingleNumType() {
+        checkTypeFlags(SingleNumTypeC.class, "mInt",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | 
TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(SingleNumTypeC.class, "mLong",
+                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mShort",
+                TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mByte",
+                TypeFlags.BYTE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.ACCEPTS_ANY_OBJECT);
+        checkTypeFlags(SingleNumTypeC.class, "mDouble",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mFloat",
+                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mUnknown",
+                TypeFlags.UNKNOWN_NUMERICAL_TYPE | TypeFlags.ACCEPTS_NUMBER);
+        
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.BIG_DECIMAL | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER);
+    }
+    
+    static public class SingleNumTypeC {
+        public void mInt(int a1, String a2) { }
+        public void mInt(int a1, int a2) { }
+        public void mLong(long a1) { }
+        public void mLong(Long a1) { }
+        public void mShort(short a1) { }
+        public void mByte(byte a1, boolean a2) { }
+        public void mByte(byte a1, String a2) { }
+        public void mByte(byte a1, Object a2) { }
+        public void mDouble(double a1) { }
+        public void mFloat(float a1) { }
+        public void mUnknown(RationalNumber a1) { };
+        
+        public void mVarParamCnt(BigDecimal a1) { }
+        public void mVarParamCnt(BigInteger a1, Double a2) { }
+        public void mVarParamCnt(Double a1,     Float a2, Integer a3) { }
+        public void mVarParamCnt(Object a1,     char a2,  boolean a3, File a4, 
Map a5,    Boolean a6) { }
+        public void mVarParamCnt(Long a1,       int a2,   short a3,   byte a4, 
double a5, float a6) { }
+    }
+
+    public void testMultipleNumTypes() {
+        checkTypeFlags(MultiNumTypeC.class, "m1",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.BYTE | TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m2",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.SHORT | TypeFlags.LONG | TypeFlags.FLOAT
+                | TypeFlags.ACCEPTS_NUMBER | TypeFlags.CHARACTER
+                );
+
+        checkTypeFlags(MultiNumTypeC.class, "m3",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.BIG_DECIMAL | TypeFlags.BIG_INTEGER
+                | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.BIG_DECIMAL | TypeFlags.UNKNOWN_NUMERICAL_TYPE
+                | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m4",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.FLOAT 
| TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.CHARACTER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m5",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.FLOAT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m6",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 2), 
OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 2), 
OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 3), 
OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 3), 
OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        checkTypeFlags(MultiNumTypeC.class, "m6",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE 
| TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE 
| TypeFlags.ACCEPTS_NUMBER,
+                0
+                );
+    }
+    
+    static public class MultiNumTypeC {
+        public void m1(byte a1) { };
+        public void m1(int a1) { };
+        public void m1(double a2) { };
+        
+        public void m2(short a1) { };
+        public void m2(long a1) { };
+        public void m2(float a1) { };
+        public void m2(char a1) { };
+        
+        public void m3(BigInteger a1, BigInteger a2, BigDecimal a3) { };
+        public void m3(BigDecimal a1, BigInteger a2, RationalNumber a3) { };
+        
+        public void m4(float a1) { };
+        public void m4(char a1) { };
+        
+        public void m5(Float a1) { };
+        public void m5(Double a1) { };
+        public void m5(Enum a1) { };
+        
+        public void m6(int a1) { };
+        public void m6(File a1, Throwable a2) { };
+        public void m6(File a1, Throwable a2, StringBuilder a3) { };
+        public void m6(File a1, Throwable a2, Throwable a3) { };
+        public void m6(double a1, int a2, File a3, File a4) { };
+        public void m6(File a1, int a2, double a3, File a4) { };
+    }
+
+    public void testVarargsNums() {
+        checkTypeFlags(VarArgsC.class, "m1",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m2",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.BIG_DECIMAL | 
TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m4",
+                TypeFlags.INTEGER | TypeFlags.LONG
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m5",
+                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m6",
+                TypeFlags.LONG | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.ACCEPTS_STRING
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m7",
+                TypeFlags.INTEGER | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.FLOAT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+
+        checkTypeFlags(VarArgsC.class, "m8",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.FLOAT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m9",
+                TypeFlags.INTEGER | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m10",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m10",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m11",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m11",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m12",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m12",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m13",
+                TypeFlags.CHARACTER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(VarArgsC.class, "m13",
+                TypeFlags.CHARACTER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.UNKNOWN_NUMERICAL_TYPE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.LONG
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | 
TypeFlags.ACCEPTS_NUMBER
+                );
+    }
+    
+    static public class VarArgsC {
+        public void m1(int... va) { }
+        
+        public void m2(double a1, int... va) { }
+        
+        public void m3(int... va) { }
+        public void m3(int a1, double... va) { }
+        public void m3(int a1, double a2, BigDecimal... va) { }
+        
+        public void m4(int... va) { }
+        public void m4(long... va) { }
+
+        public void m5(Long... va) { }
+        public void m5(long... va) { }
+        
+        public void m6(long... va) { }
+        public void m6(String... va) { }
+        
+        public void m7(int a1, double... va) { }
+        public void m7(byte a1, float... va) { }
+
+        public void m8(int a1, double... va) { }
+        public void m8(int a1, float... va) { }
+        
+        public void m9(int a1, double... va) { }
+        public void m9(byte a1, double... va) { }
+        
+        public void m10(int a1, double a2, long... va) { }
+        public void m10(int a1, double... va) { }
+        
+        public void m11(int a1, short a2, long... va) { }
+        public void m11(int a1, double... va) { }
+        
+        public void m12(int a1, short a2, byte a3, long... va) { }
+        public void m12(int a1, double... va) { }
+        
+        public void m13(char a1, double a2, RationalNumber a3, Long... va) { }
+        public void m13(char a1, Double... va) { }
+    }
+    
+    public void testAllZeros() {
+        for (boolean reverse : new boolean[] { true, false }) {
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, 
getTypeFlags(AllZeroC.class, "m1", reverse, 0));
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, 
getTypeFlags(AllZeroC.class, "m2", reverse, 2));
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, 
getTypeFlags(AllZeroC.class, "m3", reverse, 1));
+        }
+    }
+    
+    static public class AllZeroC {
+        public void m1() {}
+        
+        public void m2(File a1, File a2) {}
+        
+        public void m3(File a1) {}
+        public void m3(StringBuilder a1) {}
+    }
+
+    public void testAcceptanceNonOverloaded() {
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber1",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber2",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber3",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber4",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber5",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber6",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber7",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber8",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber9",  
TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber10", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber11", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber12", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber13", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber14", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber15", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_DECIMAL);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber16", 
TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDate", 
TypeFlags.ACCEPTS_DATE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate1", 0);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mString", 
TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCharSequence", 
TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mStringBuilder", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBool", 
TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBoolean", 
TypeFlags.ACCEPTS_BOOLEAN);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap1", 
TypeFlags.ACCEPTS_MAP);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList1", 
TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet1", 
TypeFlags.ACCEPTS_SET);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCollection", 
TypeFlags.ACCEPTS_SET | TypeFlags.ACCEPTS_LIST);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar1", 
TypeFlags.CHARACTER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar2", 
TypeFlags.CHARACTER);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray1", 
TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray2", 
TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray3", 
TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray4", 
TypeFlags.ACCEPTS_ARRAY);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mObject", 
TypeFlags.ACCEPTS_ANY_OBJECT);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_NUMBER) 
!= 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_STRING) 
!= 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_BOOLEAN) 
!= 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_MAP) != 
0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_LIST) != 
0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_SET) != 
0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_ARRAY) != 
0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.CHARACTER) == 0); 
 // deliberatly 0 
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMapDate", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDateBooleanList",
+                TypeFlags.ACCEPTS_DATE, TypeFlags.ACCEPTS_BOOLEAN, 
TypeFlags.ACCEPTS_LIST);
+    }
+    
+    static public class AcceptanceNonoverloadedC {
+        public void mNumber1(Number a1) {}
+        public void mNumber2(Byte a1) {}
+        public void mNumber3(byte a1) {}
+        public void mNumber4(Short a1) {}
+        public void mNumber5(short a1) {}
+        public void mNumber6(Integer a1) {}
+        public void mNumber7(int a1) {}
+        public void mNumber8(Long a1) {}
+        public void mNumber9(long a1) {}
+        public void mNumber10(Float a1) {}
+        public void mNumber11(float a1) {}
+        public void mNumber12(Double a1) {}
+        public void mNumber13(double a1) {}
+        public void mNumber14(BigInteger a1) {}
+        public void mNumber15(BigDecimal a1) {}
+        public void mNumber16(RationalNumber a1) {}
+        
+        public void mDate(Date a1) {}
+        public void mSQLDate1(java.sql.Date a1) {}
+        public void mSQLDate2(java.sql.Timestamp a1) {}
+        
+        public void mString(String a1) {}
+        public void mCharSequence(CharSequence a1) {}
+        public void mStringBuilder(StringBuilder a1) {}
+        
+        public void mBool(boolean a1) {}
+        public void mBoolean(Boolean a1) {}
+
+        public void mMap1(Map a1) {}
+        public void mMap2(LinkedHashMap a1) {}
+        
+        public void mList1(List a1) {}
+        public void mList2(ArrayList a1) {}
+        
+        public void mSet1(Set a1) {}
+        public void mSet2(HashSet a1) {}
+        
+        public void mCollection(Collection a1) {}
+        
+        public void mMapDate(MapDate a1) {}
+
+        public void mChar1(Character a1) {}
+        public void mChar2(char a1) {}
+
+        public void mArray1(Object[] a1) {}
+        public void mArray2(int[] a1) {}
+        public void mArray3(Integer[] a1) {}
+        public void mArray4(Void[] a1) {}
+        
+        public void mObject(Object a1) {}
+        
+        public void mDateBooleanList(Date a1, boolean a2, List a3) {}
+    }
+
+    public void testAcceptanceOverloaded() {
+        checkTypeFlags(AcceptanceOverloadedC.class, "mLongDateList",
+                TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG | 
TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.ACCEPTS_DATE | TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mBoolean", 
TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mStringChar",
+                TypeFlags.ACCEPTS_STRING | TypeFlags.CHARACTER);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mStringFile", 
TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mMapObject", 
TypeFlags.ACCEPTS_ANY_OBJECT);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mSetMap", 
TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mCollectionMap",
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET | 
TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mArray", 
TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mArrayList", 
TypeFlags.ACCEPTS_ARRAY | TypeFlags.ACCEPTS_LIST);
+        
+        checkTypeFlags(AcceptanceOverloadedC.class, 
"mStringCollectionThenBooleanThenMapList",
+                TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_LIST | 
TypeFlags.ACCEPTS_SET,
+                TypeFlags.ACCEPTS_BOOLEAN,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_LIST);
+    }
+    
+    static public class AcceptanceOverloadedC {
+        public void mLongDateList(long a1) {}
+        public void mLongDateList(Date a1) {}
+        public void mLongDateList(List a1) {}
+
+        public void mBoolean(boolean a1) {}
+        public void mBoolean(Boolean a1) {}
+        
+        public void mDate(Date a1) {}
+        public void mDate(java.sql.Date a1) {}
+        public void mDate(java.sql.Timestamp a1) {}
+        
+        public void mStringChar(String a1) {}
+        public void mStringChar(char a1) {}
+        public void mStringChar(Character a1) {}
+
+        public void mStringFile(String a1) {}
+        public void mStringFile(File a1) {}
+        
+        public void mMapObject(Map a1) {}
+        public void mMapObject(Object a1) {}
+        
+        public void mSetMap(Set a1) {}
+        public void mSetMap(Map a1) {}
+        
+        public void mCollectionMap(Collection a1) {}
+        public void mCollectionMap(Map a1) {}
+        
+        public void mArray(Object[] a1) {}
+        public void mArray(int[] a1) {}
+        public void mArray(Integer[] a1) {}
+        public void mArray(Void[] a1) {}
+        
+        public void mArrayList(String[] a1) {}
+        public void mArrayList(List a1) {}
+        
+        public void mStringCollectionThenBooleanThenMapList(String a1, boolean 
a2, Map a3) {}
+        public void mStringCollectionThenBooleanThenMapList(Collection a1, 
boolean a2, Map a3) {}
+        public void mStringCollectionThenBooleanThenMapList(String a1, boolean 
a2, List a3) {}
+    }
+
+    public void testAcceptanceVarargsC() {
+        checkTypeFlags(AcceptanceVarArgsC.class, "m1",
+                TypeFlags.ACCEPTS_LIST | TypeFlags.ACCEPTS_STRING);
+        
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | 
TypeFlags.ACCEPTS_BOOLEAN,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | 
TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP);
+        
+        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
+                TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_STRING,
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.CHARACTER,
+                TypeFlags.ACCEPTS_BOOLEAN);
+    }
+    
+    static public class AcceptanceVarArgsC {
+        public void m1(List... a1) {}
+        public void m1(String... a1) {}
+
+        public void m2(Map a1, String... a2) {}
+        public void m2(Map a1, boolean a2, String... a3) {}
+        public void m2(Map... a1) {}
+        
+        public void m3(String a1, Map a2, char a3, Boolean... a4) {}
+        public void m3(boolean... a1) {}
+    }
+
+    static public class MapDate extends Date implements Map {
+    
+        @Override
+        public int size() {
+            return 0;
+        }
+    
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+    
+        @Override
+        public boolean containsKey(Object key) {
+            return false;
+        }
+    
+        @Override
+        public boolean containsValue(Object value) {
+            return false;
+        }
+    
+        @Override
+        public Object get(Object key) {
+            return null;
+        }
+    
+        @Override
+        public Object put(Object key, Object value) {
+            return null;
+        }
+    
+        @Override
+        public Object remove(Object key) {
+            return null;
+        }
+    
+        @Override
+        public void putAll(Map m) {
+        }
+    
+        @Override
+        public void clear() {
+        }
+    
+        @Override
+        public Set keySet() {
+            return null;
+        }
+    
+        @Override
+        public Collection values() {
+            return null;
+        }
+    
+        @Override
+        public Set entrySet() {
+            return null;
+        }
+        
+    }
+
+    private OverloadedMethodsSubset newOverloadedMethodsSubset(Class cl, 
String methodName, final boolean desc) {
+        final Method[] ms = cl.getMethods();
+        
+        final List<Method> filteredMethods = new ArrayList();
+        for (Method m : ms) {
+            if (m.getName().equals(methodName)) {
+                filteredMethods.add(m);
+            }
+        }
+        // As the order in which getMethods() returns the methods is 
undefined, we sort them for test predictability: 
+        Collections.sort(filteredMethods, new Comparator<Method>() {
+            @Override
+            public int compare(Method o1, Method o2) {
+                int res = o1.toString().compareTo(o2.toString());
+                return desc ? -res : res;
+            }
+        });
+        
+        final OverloadedMethodsSubset oms = cl.getName().indexOf("VarArgs") == 
-1
+                ? new OverloadedFixArgsMethods() : new 
OverloadedVarArgsMethods();
+        for (Method m : filteredMethods) {
+            oms.addCallableMemberDescriptor(new 
ReflectionCallableMemberDescriptor(m, m.getParameterTypes()));
+        }
+        return oms;
+    }
+    
+    private void checkTypeFlags(Class cl, String methodName, int... 
expectedTypeFlags) {
+        checkTypeFlags(cl, methodName, false, expectedTypeFlags);
+        checkTypeFlags(cl, methodName, true, expectedTypeFlags);
+    }
+    
+    private void checkTypeFlags(Class cl, String methodName, boolean 
revMetOrder, int... expectedTypeFlags) {
+        int[] actualParamTypes = getTypeFlags(cl, methodName, revMetOrder, 
expectedTypeFlags.length);
+        assertNotNull("Method " + methodName + "(#" + expectedTypeFlags.length 
+ ") doesn't exist", actualParamTypes);
+        if (actualParamTypes != OverloadedMethodsSubset.ALL_ZEROS_ARRAY) {
+            assertEquals(expectedTypeFlags.length, actualParamTypes.length);
+            for (int i = 0; i < expectedTypeFlags.length; i++) {
+                assertEquals(expectedTypeFlags[i], actualParamTypes[i]);
+            }
+        } else {
+            for (int expectedTypeFlag : expectedTypeFlags) {
+                assertEquals(expectedTypeFlag, 0);
+            }
+        }
+    }
+
+    private int[] getTypeFlags(Class cl, String methodName, boolean 
revMetOrder, int paramCnt) {
+        OverloadedMethodsSubset oms = newOverloadedMethodsSubset(cl, 
methodName, revMetOrder);
+        int[] actualParamTypes = oms.getTypeFlags(paramCnt);
+        return actualParamTypes;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/AbstractParallelIntrospectionTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/AbstractParallelIntrospectionTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/AbstractParallelIntrospectionTest.java
deleted file mode 100644
index 62c4251..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/AbstractParallelIntrospectionTest.java
+++ /dev/null
@@ -1,125 +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.beans;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-
-import junit.framework.TestCase;
-
-public abstract class AbstractParallelIntrospectionTest extends TestCase {
-    
-    private static final int NUM_THREADS = 8;
-    private static final int NUM_ENTITYES = 8;
-    private static final int NUM_MEMBERS = 8;
-    private static final int ITERATIONS = 20000;
-    private static final double CACHE_CLEARING_CHANCE = 0.01;
-    
-    private BeansWrapper beansWrapper = new 
BeansWrapper(Configuration.VERSION_3_0_0);
-    
-    public AbstractParallelIntrospectionTest(String name) {
-        super(name);
-    }
-    
-    public void testReliability() {
-        testReliability(ITERATIONS);
-    }
-    
-    public void testReliability(int iterations) {
-        TestThread[] ts = new TestThread[NUM_THREADS]; 
-        for (int i = 0; i < NUM_THREADS; i++) {
-            ts[i] = new TestThread(iterations);
-            ts[i].start();
-        }
-
-        for (int i = 0; i < NUM_THREADS; i++) {
-            try {
-                ts[i].join();
-                if (ts[i].error != null) {
-                    throw new AssertionError(ts[i].error);
-                }
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    protected abstract TemplateHashModel getWrappedEntity(int objIdx) throws 
TemplateModelException;
-    
-    protected final BeansWrapper getBeansWrapper() {
-        return beansWrapper;
-    }
-    
-    private class TestThread extends Thread {
-        
-        private final int iterations;
-        
-        private Throwable error;
-        
-        private TestThread(int iterations) {
-            this.iterations = iterations;
-        }
-
-        @Override
-        public void run() {
-            try {
-                for (int i = 0; i < iterations; i++) {
-                    if (Math.random() < CACHE_CLEARING_CHANCE) {
-                        beansWrapper.clearClassIntrospecitonCache();
-                    }
-                    int objIdx = (int) (Math.random() * NUM_ENTITYES);
-                    TemplateHashModel h = getWrappedEntity(objIdx);
-                    int mIdx = (int) (Math.random() * NUM_MEMBERS);
-                    testProperty(h, objIdx, mIdx);
-                    testMethod(h, objIdx, mIdx);
-                }
-            } catch (Throwable e) {
-                error = e;
-            }
-        }
-
-        private void testProperty(TemplateHashModel h, int objIdx, int mIdx)
-                throws TemplateModelException, AssertionError {
-            TemplateNumberModel pv = (TemplateNumberModel) h.get("p" + mIdx);
-            final int expected = objIdx * 1000 + mIdx;
-            final int got = pv.getAsNumber().intValue();
-            if (got != expected) {
-                throw new AssertionError("Property assertation failed; " +
-                        "expected " + expected + ", but got " + got);
-            }
-        }
-
-        private void testMethod(TemplateHashModel h, int objIdx, int mIdx)
-                throws TemplateModelException, AssertionError {
-            TemplateMethodModel pv = (TemplateMethodModel) h.get("m" + mIdx);
-            final int expected = objIdx * 1000 + mIdx;
-            final int got = ((TemplateNumberModel) 
pv.exec(null)).getAsNumber().intValue();
-            if (got != expected) {
-                throw new AssertionError("Method assertation failed; " +
-                        "expected " + expected + ", but got " + got);
-            }
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/AlphabeticalMethodSorter.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/AlphabeticalMethodSorter.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/AlphabeticalMethodSorter.java
deleted file mode 100644
index 57611f1..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/AlphabeticalMethodSorter.java
+++ /dev/null
@@ -1,49 +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.beans;
-
-import java.beans.MethodDescriptor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-
-class AlphabeticalMethodSorter implements MethodSorter {
-
-    private final boolean desc;
-    
-    public AlphabeticalMethodSorter(boolean desc) {
-        this.desc = desc;
-    }
-
-    @Override
-    public MethodDescriptor[] sortMethodDescriptors(MethodDescriptor[] 
methodDescriptors) {
-        ArrayList<MethodDescriptor> ls = new 
ArrayList<>(Arrays.asList(methodDescriptors));
-        Collections.sort(ls, new Comparator<MethodDescriptor>() {
-            @Override
-            public int compare(MethodDescriptor o1, MethodDescriptor o2) {
-                int res = 
o1.getMethod().toString().compareTo(o2.getMethod().toString());
-                return desc ? -res : res;
-            }
-        });
-        return ls.toArray(new MethodDescriptor[ls.size()]);
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansAPINewInstanceTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansAPINewInstanceTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansAPINewInstanceTest.java
deleted file mode 100644
index 34e2a4f..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansAPINewInstanceTest.java
+++ /dev/null
@@ -1,134 +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.beans;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.test.util.TestUtil;
-
-import junit.framework.TestCase;
-
-public class BeansAPINewInstanceTest extends TestCase {
-
-    private BeansWrapper beansWrapper = new 
BeansWrapperBuilder(Configuration.VERSION_3_0_0).build();
-
-    public BeansAPINewInstanceTest(String name) {
-        super(name);
-    }
-    
-    @SuppressWarnings("boxing")
-    public void test() throws Exception {
-        testClassConstructors("");
-        testClassConstructors("int... [1]", 1);
-        testClassConstructors("int 1, int 2", 1, 2);
-        testClassConstructors("int... [1, 2, 3]", 1, 2, 3);
-        testClassConstructors("int... [1, 2, 3]", 1, (byte) 2, (short) 3);
-        try {
-            testClassConstructors("int... [1, 2, 3]", 1, 2, (long) 3);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        
-        testClassConstructors("int 1, int 2", (byte) 1, (short) 2);
-        testClassConstructors("double 1.0, double 2.0", (long) 1, (short) 2);
-        testClassConstructors("double 1.0, double 2.0", 1, 2f);
-        testClassConstructors("Integer null, Integer null", null, null);
-        testClassConstructors("Integer null, Integer 1", null, 1);
-        testClassConstructors("int 1, String s", 1, "s");
-        testClassConstructors("int 1, String null", 1, null);
-        testClassConstructors("Object null, Object s", null, "s");
-        testClassConstructors("Object 1.0, Object s", 1f, "s");
-        
-        testClassConstructors("Object s, int... [1, 2]", "s", 1, 2);
-        testClassConstructors("Object s, int... []", "s");
-        
-        testClassConstructors2("int 1, int 2", (byte) 1, (short) 2);
-        try {
-            testClassConstructors2("int 1, int 2", 1, 2L);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("", "", "");
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("int 1", 1);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("");
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-    }
-    
-    private void testClassConstructors(String expected, Object... args) throws 
Exception {
-        testCall(expected, Constructors.class, args); 
-    }
-
-    private void testClassConstructors2(String expected, Object... args) 
throws Exception {
-        testCall(expected, Constructors2.class, args); 
-    }
-    
-    private void testCall(String expected, Class cl, Object... args) throws 
Exception {
-        Object obj = _BeansAPI.newInstance(cl, args, beansWrapper); 
-        assertEquals(expected, obj.toString());        
-    }
-    
-    public static class Constructors {
-        private final String s;
-
-        public Constructors() { s = ""; }
-        
-        public Constructors(int x, int y) { s = "int " + x + ", int " + y; }
-        public Constructors(int x, String y) { s = "int " + x + ", String " + 
y; }
-        public Constructors(int x, long y) { s = "int " + x + ", long " + y; }
-        public Constructors(double x, double y) { s = "double " + x + ", 
double " + y; }
-        public Constructors(Integer x, Integer y) { s = "Integer " + x + ", 
Integer " + y; }
-        public Constructors(Object x, Object y) { s = "Object " + x + ", 
Object " + y; }
-
-        public Constructors(int... xs) { s = "int... " + 
TestUtil.arrayToString(xs); }
-        public Constructors(Object x, int... ys) { s = "Object " + x + ", 
int... " + TestUtil.arrayToString(ys); }
-        
-        @Override
-        public String toString() {
-            return s;
-        }
-    }
-
-    public static class Constructors2 {
-        private final String s;
-
-        public Constructors2(int x, int y) { s = "int " + x + ", int " + y; }
-        
-        @Override
-        public String toString() {
-            return s;
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperBasics.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperBasics.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperBasics.java
deleted file mode 100644
index bc6b8d7..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperBasics.java
+++ /dev/null
@@ -1,62 +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.beans;
-
-import static org.junit.Assert.*;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class BeansWrapperBasics {
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testAPIBuiltInSupport() throws TemplateModelException {
-        {
-            BeansWrapper bw = new 
BeansWrapperBuilder(Configuration.VERSION_3_0_0).build();
-            assertWrappingResult(StringModel.class, bw.wrap("s"));
-            assertWrappingResult(NumberModel.class, bw.wrap(1.5));
-            assertWrappingResult(BooleanModel.class, bw.wrap(true));
-            assertWrappingResult(CollectionModel.class, 
bw.wrap(ImmutableList.of(1)));
-            assertWrappingResult(MapModel.class, bw.wrap(ImmutableMap.of("a", 
1)));
-        }
-        
-        {
-            BeansWrapperBuilder bwb = new 
BeansWrapperBuilder(Configuration.VERSION_3_0_0);
-            bwb.setSimpleMapWrapper(true);
-            BeansWrapper bw = bwb.build();
-            assertWrappingResult(SimpleMapModel.class, 
bw.wrap(ImmutableMap.of("a", 1)));
-        }
-    }
-
-    private void assertWrappingResult(Class<? extends TemplateModel> 
expectedClass, TemplateModel tm)
-            throws TemplateModelException {
-        assertTrue(expectedClass.isInstance(tm));
-        // All BeansWrapper products support `?api`:
-        assertTrue(((TemplateModelWithAPISupport) tm).getAPI() instanceof 
APIModel);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperCachesTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperCachesTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperCachesTest.java
deleted file mode 100644
index 8221a36..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperCachesTest.java
+++ /dev/null
@@ -1,99 +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.beans;
-
-import static org.junit.Assert.*;
-
-import java.lang.ref.Reference;
-
-import org.apache.freemarker.core.Configuration;
-import 
org.apache.freemarker.core.model.impl.beans.BeansWrapper.MethodAppearanceDecision;
-import 
org.apache.freemarker.core.model.impl.beans.BeansWrapper.MethodAppearanceDecisionInput;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class BeansWrapperCachesTest {
-
-    @Test
-    public void introspectionSettingChanges() {
-        BeansWrapper bw = new BeansWrapper(Configuration.VERSION_3_0_0);
-        ClassIntrospector ci1 = bw.getClassIntrospector();
-        checkRegisteredModelFactories(ci1, bw.getStaticModels(), 
bw.getEnumModels(), bw.getModelCache());
-        
-        bw.setExposeFields(true);
-        ClassIntrospector ci2 = bw.getClassIntrospector();
-        assertNotSame(ci1, ci2);
-        checkRegisteredModelFactories(ci1);
-        checkRegisteredModelFactories(ci2, bw.getStaticModels(), 
bw.getEnumModels(), bw.getModelCache());
-        
-        bw.setExposureLevel(BeansWrapper.EXPOSE_ALL);
-        ClassIntrospector ci3 = bw.getClassIntrospector();
-        assertNotSame(ci2, ci3);
-        checkRegisteredModelFactories(ci2);
-        checkRegisteredModelFactories(ci3, bw.getStaticModels(), 
bw.getEnumModels(), bw.getModelCache());
-        
-        MethodAppearanceFineTuner maf = new MethodAppearanceFineTuner() {
-            @Override
-            public void process(MethodAppearanceDecisionInput in, 
MethodAppearanceDecision out) {
-                // nop
-            }
-        };
-        bw.setMethodAppearanceFineTuner(maf);
-        ClassIntrospector ci4 = bw.getClassIntrospector();
-        assertNotSame(ci3, ci4);
-        checkRegisteredModelFactories(ci3);
-        checkRegisteredModelFactories(ci4, bw.getStaticModels(), 
bw.getEnumModels(), bw.getModelCache());
-        
-        bw.setExposeFields(true);
-        assertSame(ci4, bw.getClassIntrospector());
-        bw.setExposureLevel(BeansWrapper.EXPOSE_ALL);
-        assertSame(ci4, bw.getClassIntrospector());
-        bw.setMethodAppearanceFineTuner(maf);
-        assertSame(ci4, bw.getClassIntrospector());
-        checkRegisteredModelFactories(ci4, bw.getStaticModels(), 
bw.getEnumModels(), bw.getModelCache());
-    }
-    
-    private void checkRegisteredModelFactories(ClassIntrospector ci, Object... 
expected) {
-        Object[] actualRefs = ci.getRegisteredModelFactoriesSnapshot();
-
-        scanActuals: for (Object actaulRef : actualRefs) {
-            Object actualItem = ((Reference) actaulRef).get();
-            for (Object expectedItem : expected) {
-                if (actualItem == expectedItem) {
-                    continue scanActuals;
-                }
-            }
-            fail("Actaul item " + actualItem + " is not among the expected 
items");
-        }
-        
-        scanExpecteds: for (Object expectedItem : expected) {
-            for (Object ref : actualRefs) {
-                Object actualItem = ((Reference) ref).get();
-                if (actualItem == expectedItem) {
-                    continue scanExpecteds;
-                }
-            }
-            fail("Expected item " + expectedItem + " is not among the actual 
items");
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperDesc.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperDesc.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperDesc.java
deleted file mode 100644
index 6fd9a8c..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperDesc.java
+++ /dev/null
@@ -1,30 +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.beans;
-
-import org.apache.freemarker.core.Configuration;
-
-public class BeansWrapperDesc extends BeansWrapperWithShortedMethods {
-
-    public BeansWrapperDesc() {
-        super(Configuration.VERSION_3_0_0, true);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperInc.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperInc.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperInc.java
deleted file mode 100644
index b347b95..0000000
--- 
a/src/test/java/org/apache/freemarker/core/model/impl/beans/BeansWrapperInc.java
+++ /dev/null
@@ -1,30 +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.beans;
-
-import org.apache.freemarker.core.Configuration;
-
-public class BeansWrapperInc extends BeansWrapperWithShortedMethods {
-
-    public BeansWrapperInc() {
-        super(Configuration.VERSION_3_0_0, false);
-    }
-
-}


Reply via email to