http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
new file mode 100644
index 0000000..9307a00
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
@@ -0,0 +1,102 @@
+/*
+ * 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.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Version;
+
+/**
+ * A hack to keep some unit tests producing exactly the same results on Java 8 
as on Java 5-7, by hiding members
+ * added after Java 7.
+ */
+public class Java7MembersOnlyDefaultObjectWrapper extends DefaultObjectWrapper 
{
+    
+    private static final Set<String> POST_JAVA_7_MAP_METHODS = newHashSet(
+            "compute", "computeIfAbsent", "computeIfPresent",
+            "forEach", "getOrDefault", "merge", "putIfAbsent", "replace", 
"replaceAll");
+
+    private static final Set<String> POST_JAVA_7_ITERABLE_METHODS = 
newHashSet("forEach");
+    private static final Set<String> POST_JAVA_7_COLLECTION_METHODS = 
newHashSet("parallelStream", "removeIf", "stream");
+    private static final Set<String> POST_JAVA_7_LIST_METHODS = 
newHashSet("sort", "spliterator");
+    
+    MethodAppearanceFineTuner POST_JAVA_7_FILTER = new 
MethodAppearanceFineTuner() {
+
+        @Override
+        public void process(DecisionInput in, Decision out) {
+            Method m = in.getMethod();
+            Class declCl = m.getDeclaringClass();
+            if (Map.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_MAP_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (Iterable.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_ITERABLE_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (Collection.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_COLLECTION_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (List.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_LIST_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+        }
+
+        private void hideMember(Decision out) {
+            out.setExposeMethodAs(null);
+            out.setExposeAsProperty(null);
+        }
+        
+    };
+    
+    public Java7MembersOnlyDefaultObjectWrapper(Version version) {
+        super(version);
+        setMethodAppearanceFineTuner(POST_JAVA_7_FILTER);
+    }
+
+    private static <T> Set<T> newHashSet(T... items) {
+        HashSet<T> r = new HashSet<>();
+        for (T item : items) {
+            r.add(item);
+        }
+        return r;
+    }
+
+    public Java7MembersOnlyDefaultObjectWrapper() {
+        this(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
new file mode 100644
index 0000000..44ef2f5
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
@@ -0,0 +1,249 @@
+/*
+ * 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;
+
+// FMPP template source:
+// ----
+// package org.apache.freemarker.core.model.impl;
+// 
+// // FMPP template source:
+// // ----
+// <#assign src><#include "ManyObjectsOfDifferentClasses.java.ftl" 
parse=false></#assign>
+// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
+// // ----
+// 
+// <#assign MAX_CLA = 8 - 1>
+// <#assign MAX_MET = 10 - 1>
+// <#assign MAX_PRO = 10 - 1>
+// 
+// public class ManyObjectsOfDifferentClasses {
+// 
+//     public static final Object[] OBJECTS = new Object[] {
+//         <#list 0..MAX_CLA as claI>
+//         new C${claI}(),
+//         </#list>
+//     };
+// 
+//     <#list 0..MAX_CLA as claI>
+//     static public class C${claI} {
+//         <#list 0..MAX_PRO as proI>
+//         public int getP${proI}() { return ${claI} * 1000 + ${proI}; }
+//         </#list>
+//         <#list 0..MAX_MET as metI>
+//         public int m${metI}() { return ${claI} * 1000 + ${metI}; };
+//         </#list>
+//     }
+//     </#list>
+//     
+// }
+// ----
+
+
+public class ManyObjectsOfDifferentClasses {
+
+    public static final Object[] OBJECTS = new Object[] {
+        new C0(),
+        new C1(),
+        new C2(),
+        new C3(),
+        new C4(),
+        new C5(),
+        new C6(),
+        new C7(),
+    };
+
+    static public class C0 {
+        public int getP0() { return 0 * 1000 + 0; }
+        public int getP1() { return 0 * 1000 + 1; }
+        public int getP2() { return 0 * 1000 + 2; }
+        public int getP3() { return 0 * 1000 + 3; }
+        public int getP4() { return 0 * 1000 + 4; }
+        public int getP5() { return 0 * 1000 + 5; }
+        public int getP6() { return 0 * 1000 + 6; }
+        public int getP7() { return 0 * 1000 + 7; }
+        public int getP8() { return 0 * 1000 + 8; }
+        public int getP9() { return 0 * 1000 + 9; }
+        public int m0() { return 0 * 1000 + 0; };
+        public int m1() { return 0 * 1000 + 1; };
+        public int m2() { return 0 * 1000 + 2; };
+        public int m3() { return 0 * 1000 + 3; };
+        public int m4() { return 0 * 1000 + 4; };
+        public int m5() { return 0 * 1000 + 5; };
+        public int m6() { return 0 * 1000 + 6; };
+        public int m7() { return 0 * 1000 + 7; };
+        public int m8() { return 0 * 1000 + 8; };
+        public int m9() { return 0 * 1000 + 9; };
+    }
+    static public class C1 {
+        public int getP0() { return 1 * 1000 + 0; }
+        public int getP1() { return 1 * 1000 + 1; }
+        public int getP2() { return 1 * 1000 + 2; }
+        public int getP3() { return 1 * 1000 + 3; }
+        public int getP4() { return 1 * 1000 + 4; }
+        public int getP5() { return 1 * 1000 + 5; }
+        public int getP6() { return 1 * 1000 + 6; }
+        public int getP7() { return 1 * 1000 + 7; }
+        public int getP8() { return 1 * 1000 + 8; }
+        public int getP9() { return 1 * 1000 + 9; }
+        public int m0() { return 1 * 1000 + 0; };
+        public int m1() { return 1 * 1000 + 1; };
+        public int m2() { return 1 * 1000 + 2; };
+        public int m3() { return 1 * 1000 + 3; };
+        public int m4() { return 1 * 1000 + 4; };
+        public int m5() { return 1 * 1000 + 5; };
+        public int m6() { return 1 * 1000 + 6; };
+        public int m7() { return 1 * 1000 + 7; };
+        public int m8() { return 1 * 1000 + 8; };
+        public int m9() { return 1 * 1000 + 9; };
+    }
+    static public class C2 {
+        public int getP0() { return 2 * 1000 + 0; }
+        public int getP1() { return 2 * 1000 + 1; }
+        public int getP2() { return 2 * 1000 + 2; }
+        public int getP3() { return 2 * 1000 + 3; }
+        public int getP4() { return 2 * 1000 + 4; }
+        public int getP5() { return 2 * 1000 + 5; }
+        public int getP6() { return 2 * 1000 + 6; }
+        public int getP7() { return 2 * 1000 + 7; }
+        public int getP8() { return 2 * 1000 + 8; }
+        public int getP9() { return 2 * 1000 + 9; }
+        public int m0() { return 2 * 1000 + 0; };
+        public int m1() { return 2 * 1000 + 1; };
+        public int m2() { return 2 * 1000 + 2; };
+        public int m3() { return 2 * 1000 + 3; };
+        public int m4() { return 2 * 1000 + 4; };
+        public int m5() { return 2 * 1000 + 5; };
+        public int m6() { return 2 * 1000 + 6; };
+        public int m7() { return 2 * 1000 + 7; };
+        public int m8() { return 2 * 1000 + 8; };
+        public int m9() { return 2 * 1000 + 9; };
+    }
+    static public class C3 {
+        public int getP0() { return 3 * 1000 + 0; }
+        public int getP1() { return 3 * 1000 + 1; }
+        public int getP2() { return 3 * 1000 + 2; }
+        public int getP3() { return 3 * 1000 + 3; }
+        public int getP4() { return 3 * 1000 + 4; }
+        public int getP5() { return 3 * 1000 + 5; }
+        public int getP6() { return 3 * 1000 + 6; }
+        public int getP7() { return 3 * 1000 + 7; }
+        public int getP8() { return 3 * 1000 + 8; }
+        public int getP9() { return 3 * 1000 + 9; }
+        public int m0() { return 3 * 1000 + 0; };
+        public int m1() { return 3 * 1000 + 1; };
+        public int m2() { return 3 * 1000 + 2; };
+        public int m3() { return 3 * 1000 + 3; };
+        public int m4() { return 3 * 1000 + 4; };
+        public int m5() { return 3 * 1000 + 5; };
+        public int m6() { return 3 * 1000 + 6; };
+        public int m7() { return 3 * 1000 + 7; };
+        public int m8() { return 3 * 1000 + 8; };
+        public int m9() { return 3 * 1000 + 9; };
+    }
+    static public class C4 {
+        public int getP0() { return 4 * 1000 + 0; }
+        public int getP1() { return 4 * 1000 + 1; }
+        public int getP2() { return 4 * 1000 + 2; }
+        public int getP3() { return 4 * 1000 + 3; }
+        public int getP4() { return 4 * 1000 + 4; }
+        public int getP5() { return 4 * 1000 + 5; }
+        public int getP6() { return 4 * 1000 + 6; }
+        public int getP7() { return 4 * 1000 + 7; }
+        public int getP8() { return 4 * 1000 + 8; }
+        public int getP9() { return 4 * 1000 + 9; }
+        public int m0() { return 4 * 1000 + 0; };
+        public int m1() { return 4 * 1000 + 1; };
+        public int m2() { return 4 * 1000 + 2; };
+        public int m3() { return 4 * 1000 + 3; };
+        public int m4() { return 4 * 1000 + 4; };
+        public int m5() { return 4 * 1000 + 5; };
+        public int m6() { return 4 * 1000 + 6; };
+        public int m7() { return 4 * 1000 + 7; };
+        public int m8() { return 4 * 1000 + 8; };
+        public int m9() { return 4 * 1000 + 9; };
+    }
+    static public class C5 {
+        public int getP0() { return 5 * 1000 + 0; }
+        public int getP1() { return 5 * 1000 + 1; }
+        public int getP2() { return 5 * 1000 + 2; }
+        public int getP3() { return 5 * 1000 + 3; }
+        public int getP4() { return 5 * 1000 + 4; }
+        public int getP5() { return 5 * 1000 + 5; }
+        public int getP6() { return 5 * 1000 + 6; }
+        public int getP7() { return 5 * 1000 + 7; }
+        public int getP8() { return 5 * 1000 + 8; }
+        public int getP9() { return 5 * 1000 + 9; }
+        public int m0() { return 5 * 1000 + 0; };
+        public int m1() { return 5 * 1000 + 1; };
+        public int m2() { return 5 * 1000 + 2; };
+        public int m3() { return 5 * 1000 + 3; };
+        public int m4() { return 5 * 1000 + 4; };
+        public int m5() { return 5 * 1000 + 5; };
+        public int m6() { return 5 * 1000 + 6; };
+        public int m7() { return 5 * 1000 + 7; };
+        public int m8() { return 5 * 1000 + 8; };
+        public int m9() { return 5 * 1000 + 9; };
+    }
+    static public class C6 {
+        public int getP0() { return 6 * 1000 + 0; }
+        public int getP1() { return 6 * 1000 + 1; }
+        public int getP2() { return 6 * 1000 + 2; }
+        public int getP3() { return 6 * 1000 + 3; }
+        public int getP4() { return 6 * 1000 + 4; }
+        public int getP5() { return 6 * 1000 + 5; }
+        public int getP6() { return 6 * 1000 + 6; }
+        public int getP7() { return 6 * 1000 + 7; }
+        public int getP8() { return 6 * 1000 + 8; }
+        public int getP9() { return 6 * 1000 + 9; }
+        public int m0() { return 6 * 1000 + 0; };
+        public int m1() { return 6 * 1000 + 1; };
+        public int m2() { return 6 * 1000 + 2; };
+        public int m3() { return 6 * 1000 + 3; };
+        public int m4() { return 6 * 1000 + 4; };
+        public int m5() { return 6 * 1000 + 5; };
+        public int m6() { return 6 * 1000 + 6; };
+        public int m7() { return 6 * 1000 + 7; };
+        public int m8() { return 6 * 1000 + 8; };
+        public int m9() { return 6 * 1000 + 9; };
+    }
+    static public class C7 {
+        public int getP0() { return 7 * 1000 + 0; }
+        public int getP1() { return 7 * 1000 + 1; }
+        public int getP2() { return 7 * 1000 + 2; }
+        public int getP3() { return 7 * 1000 + 3; }
+        public int getP4() { return 7 * 1000 + 4; }
+        public int getP5() { return 7 * 1000 + 5; }
+        public int getP6() { return 7 * 1000 + 6; }
+        public int getP7() { return 7 * 1000 + 7; }
+        public int getP8() { return 7 * 1000 + 8; }
+        public int getP9() { return 7 * 1000 + 9; }
+        public int m0() { return 7 * 1000 + 0; };
+        public int m1() { return 7 * 1000 + 1; };
+        public int m2() { return 7 * 1000 + 2; };
+        public int m3() { return 7 * 1000 + 3; };
+        public int m4() { return 7 * 1000 + 4; };
+        public int m5() { return 7 * 1000 + 5; };
+        public int m6() { return 7 * 1000 + 6; };
+        public int m7() { return 7 * 1000 + 7; };
+        public int m8() { return 7 * 1000 + 8; };
+        public int m9() { return 7 * 1000 + 9; };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
new file mode 100644
index 0000000..a3f6f36
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
@@ -0,0 +1,236 @@
+/*
+ * 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;
+
+// FMPP template source:
+// ----
+// package org.apache.freemarker.core.model.impl;
+// 
+// // FMPP template source:
+// // ----
+// <#assign src><#include "ManyStaticsOfDifferentClasses.java.ftl" 
parse=false></#assign>
+// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
+// // ----
+// 
+// <#assign MAX_CLA = 8 - 1>
+// <#assign MAX_MET = 10 - 1>
+// <#assign MAX_PRO = 10 - 1>
+// 
+// public class ManyStaticsOfDifferentClasses {
+// 
+//     private ManyStaticsOfDifferentClasses() { }
+// 
+//     <#list 0..MAX_CLA as claI>
+//     static public class C${claI} {
+//         <#list 0..MAX_PRO as proI>
+//         public static int p${proI} = ${claI} * 1000 + ${proI};
+//         </#list>
+//         <#list 0..MAX_MET as metI>
+//         public static int m${metI}() { return ${claI} * 1000 + ${metI}; };
+//         </#list>
+//     }
+//     </#list>
+//     
+// }
+// ----
+
+
+public class ManyStaticsOfDifferentClasses {
+
+    private ManyStaticsOfDifferentClasses() { }
+
+    static public class C0 {
+        public static int p0 = 0 * 1000 + 0;
+        public static int p1 = 0 * 1000 + 1;
+        public static int p2 = 0 * 1000 + 2;
+        public static int p3 = 0 * 1000 + 3;
+        public static int p4 = 0 * 1000 + 4;
+        public static int p5 = 0 * 1000 + 5;
+        public static int p6 = 0 * 1000 + 6;
+        public static int p7 = 0 * 1000 + 7;
+        public static int p8 = 0 * 1000 + 8;
+        public static int p9 = 0 * 1000 + 9;
+        public static int m0() { return 0 * 1000 + 0; };
+        public static int m1() { return 0 * 1000 + 1; };
+        public static int m2() { return 0 * 1000 + 2; };
+        public static int m3() { return 0 * 1000 + 3; };
+        public static int m4() { return 0 * 1000 + 4; };
+        public static int m5() { return 0 * 1000 + 5; };
+        public static int m6() { return 0 * 1000 + 6; };
+        public static int m7() { return 0 * 1000 + 7; };
+        public static int m8() { return 0 * 1000 + 8; };
+        public static int m9() { return 0 * 1000 + 9; };
+    }
+    static public class C1 {
+        public static int p0 = 1 * 1000 + 0;
+        public static int p1 = 1 * 1000 + 1;
+        public static int p2 = 1 * 1000 + 2;
+        public static int p3 = 1 * 1000 + 3;
+        public static int p4 = 1 * 1000 + 4;
+        public static int p5 = 1 * 1000 + 5;
+        public static int p6 = 1 * 1000 + 6;
+        public static int p7 = 1 * 1000 + 7;
+        public static int p8 = 1 * 1000 + 8;
+        public static int p9 = 1 * 1000 + 9;
+        public static int m0() { return 1 * 1000 + 0; };
+        public static int m1() { return 1 * 1000 + 1; };
+        public static int m2() { return 1 * 1000 + 2; };
+        public static int m3() { return 1 * 1000 + 3; };
+        public static int m4() { return 1 * 1000 + 4; };
+        public static int m5() { return 1 * 1000 + 5; };
+        public static int m6() { return 1 * 1000 + 6; };
+        public static int m7() { return 1 * 1000 + 7; };
+        public static int m8() { return 1 * 1000 + 8; };
+        public static int m9() { return 1 * 1000 + 9; };
+    }
+    static public class C2 {
+        public static int p0 = 2 * 1000 + 0;
+        public static int p1 = 2 * 1000 + 1;
+        public static int p2 = 2 * 1000 + 2;
+        public static int p3 = 2 * 1000 + 3;
+        public static int p4 = 2 * 1000 + 4;
+        public static int p5 = 2 * 1000 + 5;
+        public static int p6 = 2 * 1000 + 6;
+        public static int p7 = 2 * 1000 + 7;
+        public static int p8 = 2 * 1000 + 8;
+        public static int p9 = 2 * 1000 + 9;
+        public static int m0() { return 2 * 1000 + 0; };
+        public static int m1() { return 2 * 1000 + 1; };
+        public static int m2() { return 2 * 1000 + 2; };
+        public static int m3() { return 2 * 1000 + 3; };
+        public static int m4() { return 2 * 1000 + 4; };
+        public static int m5() { return 2 * 1000 + 5; };
+        public static int m6() { return 2 * 1000 + 6; };
+        public static int m7() { return 2 * 1000 + 7; };
+        public static int m8() { return 2 * 1000 + 8; };
+        public static int m9() { return 2 * 1000 + 9; };
+    }
+    static public class C3 {
+        public static int p0 = 3 * 1000 + 0;
+        public static int p1 = 3 * 1000 + 1;
+        public static int p2 = 3 * 1000 + 2;
+        public static int p3 = 3 * 1000 + 3;
+        public static int p4 = 3 * 1000 + 4;
+        public static int p5 = 3 * 1000 + 5;
+        public static int p6 = 3 * 1000 + 6;
+        public static int p7 = 3 * 1000 + 7;
+        public static int p8 = 3 * 1000 + 8;
+        public static int p9 = 3 * 1000 + 9;
+        public static int m0() { return 3 * 1000 + 0; };
+        public static int m1() { return 3 * 1000 + 1; };
+        public static int m2() { return 3 * 1000 + 2; };
+        public static int m3() { return 3 * 1000 + 3; };
+        public static int m4() { return 3 * 1000 + 4; };
+        public static int m5() { return 3 * 1000 + 5; };
+        public static int m6() { return 3 * 1000 + 6; };
+        public static int m7() { return 3 * 1000 + 7; };
+        public static int m8() { return 3 * 1000 + 8; };
+        public static int m9() { return 3 * 1000 + 9; };
+    }
+    static public class C4 {
+        public static int p0 = 4 * 1000 + 0;
+        public static int p1 = 4 * 1000 + 1;
+        public static int p2 = 4 * 1000 + 2;
+        public static int p3 = 4 * 1000 + 3;
+        public static int p4 = 4 * 1000 + 4;
+        public static int p5 = 4 * 1000 + 5;
+        public static int p6 = 4 * 1000 + 6;
+        public static int p7 = 4 * 1000 + 7;
+        public static int p8 = 4 * 1000 + 8;
+        public static int p9 = 4 * 1000 + 9;
+        public static int m0() { return 4 * 1000 + 0; };
+        public static int m1() { return 4 * 1000 + 1; };
+        public static int m2() { return 4 * 1000 + 2; };
+        public static int m3() { return 4 * 1000 + 3; };
+        public static int m4() { return 4 * 1000 + 4; };
+        public static int m5() { return 4 * 1000 + 5; };
+        public static int m6() { return 4 * 1000 + 6; };
+        public static int m7() { return 4 * 1000 + 7; };
+        public static int m8() { return 4 * 1000 + 8; };
+        public static int m9() { return 4 * 1000 + 9; };
+    }
+    static public class C5 {
+        public static int p0 = 5 * 1000 + 0;
+        public static int p1 = 5 * 1000 + 1;
+        public static int p2 = 5 * 1000 + 2;
+        public static int p3 = 5 * 1000 + 3;
+        public static int p4 = 5 * 1000 + 4;
+        public static int p5 = 5 * 1000 + 5;
+        public static int p6 = 5 * 1000 + 6;
+        public static int p7 = 5 * 1000 + 7;
+        public static int p8 = 5 * 1000 + 8;
+        public static int p9 = 5 * 1000 + 9;
+        public static int m0() { return 5 * 1000 + 0; };
+        public static int m1() { return 5 * 1000 + 1; };
+        public static int m2() { return 5 * 1000 + 2; };
+        public static int m3() { return 5 * 1000 + 3; };
+        public static int m4() { return 5 * 1000 + 4; };
+        public static int m5() { return 5 * 1000 + 5; };
+        public static int m6() { return 5 * 1000 + 6; };
+        public static int m7() { return 5 * 1000 + 7; };
+        public static int m8() { return 5 * 1000 + 8; };
+        public static int m9() { return 5 * 1000 + 9; };
+    }
+    static public class C6 {
+        public static int p0 = 6 * 1000 + 0;
+        public static int p1 = 6 * 1000 + 1;
+        public static int p2 = 6 * 1000 + 2;
+        public static int p3 = 6 * 1000 + 3;
+        public static int p4 = 6 * 1000 + 4;
+        public static int p5 = 6 * 1000 + 5;
+        public static int p6 = 6 * 1000 + 6;
+        public static int p7 = 6 * 1000 + 7;
+        public static int p8 = 6 * 1000 + 8;
+        public static int p9 = 6 * 1000 + 9;
+        public static int m0() { return 6 * 1000 + 0; };
+        public static int m1() { return 6 * 1000 + 1; };
+        public static int m2() { return 6 * 1000 + 2; };
+        public static int m3() { return 6 * 1000 + 3; };
+        public static int m4() { return 6 * 1000 + 4; };
+        public static int m5() { return 6 * 1000 + 5; };
+        public static int m6() { return 6 * 1000 + 6; };
+        public static int m7() { return 6 * 1000 + 7; };
+        public static int m8() { return 6 * 1000 + 8; };
+        public static int m9() { return 6 * 1000 + 9; };
+    }
+    static public class C7 {
+        public static int p0 = 7 * 1000 + 0;
+        public static int p1 = 7 * 1000 + 1;
+        public static int p2 = 7 * 1000 + 2;
+        public static int p3 = 7 * 1000 + 3;
+        public static int p4 = 7 * 1000 + 4;
+        public static int p5 = 7 * 1000 + 5;
+        public static int p6 = 7 * 1000 + 6;
+        public static int p7 = 7 * 1000 + 7;
+        public static int p8 = 7 * 1000 + 8;
+        public static int p9 = 7 * 1000 + 9;
+        public static int m0() { return 7 * 1000 + 0; };
+        public static int m1() { return 7 * 1000 + 1; };
+        public static int m2() { return 7 * 1000 + 2; };
+        public static int m3() { return 7 * 1000 + 3; };
+        public static int m4() { return 7 * 1000 + 4; };
+        public static int m5() { return 7 * 1000 + 5; };
+        public static int m6() { return 7 * 1000 + 6; };
+        public static int m7() { return 7 * 1000 + 7; };
+        public static int m8() { return 7 * 1000 + 8; };
+        public static int m9() { return 7 * 1000 + 9; };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
new file mode 100644
index 0000000..148211e
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.junit.Assert;
+
+import junit.framework.TestCase;
+
+public class MiscNumericalOperationsTest extends TestCase {
+
+    public MiscNumericalOperationsTest(String name) {
+        super(name);
+    }
+    
+    public void testForceUnwrappedNumberToType() {
+        // Usual type to to all other types:
+        Double n = Double.valueOf(123.75);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Short.class), Short.valueOf(n.shortValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Short.TYPE), Short.valueOf(n.shortValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Byte.class), Byte.valueOf(n.byteValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Byte.TYPE), Byte.valueOf(n.byteValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Integer.class), Integer.valueOf(n.intValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Integer.TYPE), Integer.valueOf(n.intValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Long.class), Long.valueOf(n.longValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Long.TYPE), Long.valueOf(n.longValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Float.class), Float.valueOf(n.floatValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Float.TYPE), Float.valueOf(n.floatValue()));
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Double.class) == n);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Double.TYPE) == n);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
BigInteger.class), new BigInteger("123"));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
BigDecimal.class), new BigDecimal("123.75"));
+        
+        // Cases of conversion to BigDecimal:
+        BigDecimal bd = new BigDecimal("123");
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new 
BigInteger("123"), BigDecimal.class), bd);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bd, 
BigDecimal.class) == bd);
+        
assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), 
BigDecimal.class), bd);
+        
assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123),
 BigDecimal.class), bd);
+        
+        // Cases of conversion to BigInteger:
+        BigInteger bi = new BigInteger("123");
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new 
BigDecimal("123.6"), BigInteger.class), bi);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(
+                new OverloadedNumberUtil.IntegerBigDecimal(new 
BigDecimal("123")), BigInteger.class), bi);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bi, 
BigInteger.class) == bi);
+        
assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), 
BigInteger.class), bi);
+        
assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123.6),
 BigInteger.class), bi);
+
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
Number.class) == n);
+        assertNull(DefaultObjectWrapper.forceUnwrappedNumberToType(n, 
RationalNumber.class));
+        RationalNumber r = new RationalNumber(1, 2);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, 
RationalNumber.class) == r);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, 
Number.class) == r);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, 
Double.class), Double.valueOf(0.5));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, 
BigDecimal.class), new BigDecimal("0.5"));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, 
BigInteger.class), BigInteger.ZERO);
+    }
+    
+    @SuppressWarnings("boxing")
+    public void testForceNumberArgumentsToParameterTypes() {
+        OverloadedMethodsSubset oms = new OverloadedFixArgsMethods();
+        Class[] paramTypes = new Class[] { Short.TYPE, Short.class, 
Double.TYPE, BigDecimal.class, BigInteger.class };
+        Object[] args;
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF });
+        Assert.assertArrayEquals(
+                args,
+                new Object[] { (short) 123, (short) 123, 123.75, new 
BigDecimal("123.75"), BigInteger.valueOf(123) });
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 
0, 0, 0, 0, 0 });
+        Assert.assertArrayEquals(args, newArgs());
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 
8, 8, 8, 8, 8 });
+        Assert.assertArrayEquals(args, newArgs());
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 
0xFFFF, 0, 0xFFFF, 0, 0xFFFF });
+        Assert.assertArrayEquals(
+                args,
+                new Object[] { (short) 123, 123.75, 123.75, 123.75, 
BigInteger.valueOf(123) });
+    }
+
+    @SuppressWarnings("boxing")
+    private Object[] newArgs() {
+        return new Object[] { 123.75, 123.75, 123.75, 123.75, 123.75 };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
new file mode 100644
index 0000000..7e66b72
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.Configuration;
+import org.apache.freemarker.test.util.TestUtil;
+
+import junit.framework.TestCase;
+
+public class ModelAPINewInstanceTest extends TestCase {
+
+    private DefaultObjectWrapper ow = new 
DefaultObjectWrapperBuilder(Configuration.VERSION_3_0_0).build();
+
+    public ModelAPINewInstanceTest(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 = _ModelAPI.newInstance(cl, args, ow);
+        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/ModelCacheTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java 
b/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
new file mode 100644
index 0000000..4ad3c0e
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.junit.Assert.*;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ModelCacheTest {
+    
+    @Test
+    public void modelCacheOff() throws Exception {
+        DefaultObjectWrapper ow = new 
DefaultObjectWrapperBuilder(Configuration.VERSION_3_0_0).build();
+        assertFalse(ow.getUseModelCache());  // default is off
+        
+        String s = "foo";
+        assertNotSame(ow.wrap(s), ow.wrap(s));
+        
+        C c = new C();
+        assertNotSame(ow.wrap(c), ow.wrap(c));
+    }
+    
+    @Test
+    public void modelCacheOn() throws Exception {
+        DefaultObjectWrapper ow = new 
DefaultObjectWrapper(Configuration.VERSION_3_0_0);
+        ow.setUseModelCache(true);
+        assertTrue(ow.getUseModelCache());
+
+        TestBean obj = new TestBean();
+        assertSame(ow.wrap(obj), ow.wrap(obj));
+        
+        C c = new C();
+        TemplateModel wrappedC = ow.wrap(c);
+        assertSame(wrappedC, ow.wrap(c));
+        
+        ow.clearClassIntrospecitonCache();
+        assertNotSame(wrappedC, ow.wrap(c));
+        assertSame(ow.wrap(c), ow.wrap(c));
+    }
+
+    static public class C { }
+
+    public static class TestBean {
+        //
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
 
b/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
new file mode 100644
index 0000000..646da00
--- /dev/null
+++ 
b/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
@@ -0,0 +1,585 @@
+/*
+ * 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.math.BigDecimal;
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("boxing")
+public class OverloadedNumberUtilTest extends TestCase {
+
+    public OverloadedNumberUtilTest(String name) {
+        super(name);
+    }
+    
+    public void testIntegerCoercions() {
+        cipEqu(Byte.valueOf(Byte.MAX_VALUE));
+        cipEqu(Byte.valueOf((byte) 0));
+        cipEqu(Byte.valueOf(Byte.MIN_VALUE));
+        
+        cipEqu(Short.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.ShortOrByte((short) Byte.MAX_VALUE, 
Byte.MAX_VALUE));
+        cipEqu(Short.valueOf((short) 0),
+                new OverloadedNumberUtil.ShortOrByte((short) 0, (byte) 0));
+        cipEqu(Short.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.ShortOrByte((short) Byte.MIN_VALUE, 
Byte.MIN_VALUE));
+        
+        cipEqu(Short.valueOf((short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Short.valueOf((short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Short.valueOf(Short.MAX_VALUE));
+        cipEqu(Short.valueOf(Short.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MAX_VALUE, 
Byte.MAX_VALUE));
+        cipEqu(Integer.valueOf(0),
+                new OverloadedNumberUtil.IntegerOrByte(0, (byte) 0));
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MIN_VALUE, 
Byte.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE + 1),
+                new OverloadedNumberUtil.IntegerOrShort(Byte.MAX_VALUE + 1, 
(short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE - 1),
+                new OverloadedNumberUtil.IntegerOrShort(Byte.MIN_VALUE - 1, 
(short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Integer.valueOf(Short.MAX_VALUE),
+                new OverloadedNumberUtil.IntegerOrShort((int) Short.MAX_VALUE, 
Short.MAX_VALUE));
+        cipEqu(Integer.valueOf(Short.MIN_VALUE),
+                new OverloadedNumberUtil.IntegerOrShort((int) Short.MIN_VALUE, 
Short.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Short.MAX_VALUE + 1));
+        cipEqu(Integer.valueOf(Short.MIN_VALUE - 1));
+        cipEqu(Integer.valueOf(Integer.MAX_VALUE));
+        cipEqu(Integer.valueOf(Integer.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrByte((long) Byte.MAX_VALUE, 
Byte.MAX_VALUE));
+        cipEqu(Long.valueOf(0),
+                new OverloadedNumberUtil.LongOrByte((long) 0, (byte) 0));
+        cipEqu(Long.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrByte((long) Byte.MIN_VALUE, 
Byte.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Byte.MAX_VALUE + 1),
+                new OverloadedNumberUtil.LongOrShort((long) (Byte.MAX_VALUE + 
1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Long.valueOf(Byte.MIN_VALUE - 1),
+                new OverloadedNumberUtil.LongOrShort((long) (Byte.MIN_VALUE - 
1), (short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Long.valueOf(Short.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrShort((long) Short.MAX_VALUE, 
Short.MAX_VALUE));
+        cipEqu(Long.valueOf(Short.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrShort((long) Short.MIN_VALUE, 
Short.MIN_VALUE));
+
+        cipEqu(Long.valueOf(Short.MAX_VALUE + 1),
+                new OverloadedNumberUtil.LongOrInteger((long) Short.MAX_VALUE 
+ 1, Short.MAX_VALUE + 1));
+        cipEqu(Long.valueOf(Short.MIN_VALUE - 1),
+                new OverloadedNumberUtil.LongOrInteger((long) Short.MIN_VALUE 
- 1, Short.MIN_VALUE - 1));
+        cipEqu(Long.valueOf(Integer.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrInteger((long) 
Integer.MAX_VALUE, Integer.MAX_VALUE));
+        cipEqu(Long.valueOf(Integer.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrInteger((long) 
Integer.MIN_VALUE, Integer.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L));
+        cipEqu(Long.valueOf(Integer.MIN_VALUE - 1L));
+        cipEqu(Long.valueOf(Long.MAX_VALUE));
+        cipEqu(Long.valueOf(Long.MIN_VALUE));
+    }
+    
+    public void testIntegerNoCoercions() {
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE), 
Integer.valueOf(Byte.MAX_VALUE), 0);
+        cipEqu(Integer.valueOf(0), Integer.valueOf(0), 0);
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE), 
Integer.valueOf(Byte.MIN_VALUE), 0);
+    }
+    
+    public void testIntegerLimitedCoercions() {
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE), 
Integer.valueOf(Byte.MAX_VALUE), TypeFlags.INTEGER);
+        cipEqu(Integer.valueOf(0), Integer.valueOf(0), TypeFlags.INTEGER);
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE), 
Integer.valueOf(Byte.MIN_VALUE), TypeFlags.INTEGER);
+        
+        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L), 
Long.valueOf(Integer.MAX_VALUE + 1L), TypeFlags.INTEGER);
+        
+        for (int n = -1; n < 2; n++) {
+            final Long longN = Long.valueOf(n);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrInteger(longN, n), 
TypeFlags.INTEGER);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) 
n), TypeFlags.SHORT);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrByte(longN, (byte) 
n), TypeFlags.BYTE);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) 
n),
+                    TypeFlags.SHORT | TypeFlags.INTEGER);
+        }
+    }
+
+    public void testBigDecimalCoercions() {
+        cipEqu(new BigDecimal(123), new 
OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)));
+        cipEqu(new BigDecimal(123), new 
OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)),
+                TypeFlags.DOUBLE | TypeFlags.INTEGER);
+        cipEqu(new BigDecimal(123), TypeFlags.INTEGER);
+        cipEqu(new BigDecimal(123), TypeFlags.INTEGER | TypeFlags.LONG);
+        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE);
+        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        cipEqu(new BigDecimal(123.5));
+        // Not wasting time with check if it's a whole number if we only have 
integer-only or non-integer-only targets:  
+        cipEqu(new BigDecimal(123.5), TypeFlags.INTEGER | TypeFlags.LONG);
+        cipEqu(new BigDecimal(123.5), TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        cipEqu(new BigDecimal("0.01"));
+        cipEqu(new BigDecimal("-0.01"));
+        cipEqu(BigDecimal.ZERO, new 
OverloadedNumberUtil.IntegerBigDecimal(BigDecimal.ZERO));
+    }
+
+    public void testUnknownNumberCoercion() {
+        cipEqu(new RationalNumber(2, 3));
+    }
+
+    @SuppressWarnings("boxing")
+    public void testDoubleCoercion() {
+        cipEqu(Double.valueOf(1.5), new 
OverloadedNumberUtil.DoubleOrFloat(1.5));
+        cipEqu(Double.valueOf(-0.125), new 
OverloadedNumberUtil.DoubleOrFloat(-0.125));
+        cipEqu(Double.valueOf(Float.MAX_VALUE), new 
OverloadedNumberUtil.DoubleOrFloat((double) Float.MAX_VALUE));
+        cipEqu(Double.valueOf(-Float.MAX_VALUE), new 
OverloadedNumberUtil.DoubleOrFloat((double) -Float.MAX_VALUE));
+        cipEqu(Double.valueOf(Float.MAX_VALUE * 10.0));
+        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10.0));
+        
+        cipEqu(Double.valueOf(0), new OverloadedNumberUtil.DoubleOrByte(0.0, 
(byte) 0));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE), new 
OverloadedNumberUtil.DoubleOrByte((double) Byte.MAX_VALUE, Byte.MAX_VALUE));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE), new 
OverloadedNumberUtil.DoubleOrByte((double) Byte.MIN_VALUE, Byte.MIN_VALUE));
+        
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new 
OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new 
OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
+        
+        cipEqu(Double.valueOf(Short.MAX_VALUE + 1),
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) 
Short.MAX_VALUE + 1, Short.MAX_VALUE + 1));
+        cipEqu(Double.valueOf(Short.MIN_VALUE - 1),
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) 
Short.MIN_VALUE - 1, Short.MIN_VALUE -  1));
+        cipEqu(Double.valueOf(16777216), new 
OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216.0, 16777216));
+        cipEqu(Double.valueOf(-16777216), new 
OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216.0, -16777216));
+        
+        cipEqu(Double.valueOf(Integer.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrInteger((double) 
Integer.MAX_VALUE, Integer.MAX_VALUE));
+        cipEqu(Double.valueOf(Integer.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrInteger((double) 
Integer.MIN_VALUE, Integer.MIN_VALUE));
+        
+        cipEqu(Double.valueOf(Integer.MAX_VALUE + 1L),
+                new 
OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MAX_VALUE + 1L), 
Integer.MAX_VALUE + 1L));
+        cipEqu(Double.valueOf(Integer.MIN_VALUE - 1L),
+                new 
OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MIN_VALUE - 1L), 
Integer.MIN_VALUE - 1L));
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) 
Long.MAX_VALUE));
+        cipEqu(Double.valueOf(Long.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) 
Long.MIN_VALUE));
+
+        // When only certain target types are present:
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, 
(byte) 5), TypeFlags.BYTE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, 
(byte) 5), TypeFlags.BYTE | TypeFlags.SHORT);
+        cipEqu(Double.valueOf(-129), TypeFlags.BYTE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrShort(5.0, 
(short) 5), TypeFlags.SHORT);
+        cipEqu(Double.valueOf(5), new 
OverloadedNumberUtil.DoubleOrInteger(5.0, 5), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrLong(5.0, 
5), TypeFlags.LONG);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0), 
TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5), Double.valueOf(5), TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5.9), new 
OverloadedNumberUtil.DoubleOrFloat(5.9),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5.9),
+                TypeFlags.DOUBLE | TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5.9), new 
OverloadedNumberUtil.DoubleOrFloat(5.9),
+                TypeFlags.FLOAT | TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5.9), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) 
Long.MAX_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.LONG);
+        cipEqu(Double.valueOf(Long.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) 
Long.MIN_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(Float.MAX_VALUE * 10),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        // Rounded values:
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0));
+        cipEqu(Double.valueOf(-0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(-0.0000009, (byte) 0));
+        cipEqu(Double.valueOf(0.9999991),
+                new OverloadedNumberUtil.DoubleOrByte(0.9999991, (byte) 1));
+        cipEqu(Double.valueOf(-0.9999991),
+                new OverloadedNumberUtil.DoubleOrByte(-0.9999991, (byte) -1));
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0),
+                TypeFlags.SHORT | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009), new 
OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0),
+                TypeFlags.INTEGER | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009), new 
OverloadedNumberUtil.DoubleOrLong(0.0000009, 0),
+                TypeFlags.LONG | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0), 
TypeFlags.BYTE);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0), 
TypeFlags.SHORT);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0), 
TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrLong(0.0000009, 0L), 
TypeFlags.LONG);
+        cipEqu(Double.valueOf(0.9999999),
+                new OverloadedNumberUtil.DoubleOrInteger(0.9999999, 1), 
TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9e-6),
+                new OverloadedNumberUtil.DoubleOrByte(Byte.MAX_VALUE + 0.9e-6, 
Byte.MAX_VALUE));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9e-6),
+                new OverloadedNumberUtil.DoubleOrByte(Byte.MIN_VALUE - 0.9e-6, 
Byte.MIN_VALUE));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1.1e-6),
+                new OverloadedNumberUtil.DoubleOrFloat(Byte.MAX_VALUE + 
1.1e-6));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1.1e-6),
+                new OverloadedNumberUtil.DoubleOrFloat(Byte.MIN_VALUE - 
1.1e-6));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9999991),
+                new OverloadedNumberUtil.DoubleOrShort(
+                        Byte.MAX_VALUE + 0.9999991, (short) (Byte.MAX_VALUE + 
1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9999991),
+                new OverloadedNumberUtil.DoubleOrShort(
+                        Byte.MIN_VALUE - 0.9999991, (short) (Byte.MIN_VALUE - 
1)));
+        
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new 
OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new 
OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
+        
+        cipEqu(Short.MAX_VALUE + 0.9999991,
+                new 
OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MAX_VALUE + 0.9999991, 
Short.MAX_VALUE + 1));
+        cipEqu(Short.MIN_VALUE - 0.9999991,
+                new 
OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MIN_VALUE - 0.9999991, 
Short.MIN_VALUE - 1));
+        cipEqu(16777216 + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216 + 
0.9e-6, 16777216));
+        cipEqu(-16777216 - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216 - 
0.9e-6, -16777216));
+        
+        cipEqu(Integer.MAX_VALUE + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrInteger(Integer.MAX_VALUE + 
0.9e-6, Integer.MAX_VALUE));
+        cipEqu(Integer.MIN_VALUE - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrInteger(Integer.MIN_VALUE - 
0.9e-6, Integer.MIN_VALUE));
+        
+        cipEqu(Integer.MAX_VALUE + 1L + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Integer.MAX_VALUE + 1L 
+ 0.9e-6));
+        cipEqu(Integer.MIN_VALUE - 1L - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Integer.MIN_VALUE - 1L 
- 0.9e-6));
+        cipEqu(Long.MAX_VALUE + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Long.MAX_VALUE + 
0.9e-6));
+        cipEqu(Long.MIN_VALUE - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Long.MIN_VALUE - 
0.9e-6));
+    }
+
+    @SuppressWarnings("boxing")
+    public void testFloatCoercion() {
+        cipEqu(1.00002f);
+        cipEqu(-1.00002f);
+        cipEqu(1.999989f);
+        cipEqu(-1.999989f);
+        cipEqu(16777218f);
+        cipEqu(-16777218f);
+        
+        cipEqu(1f, new OverloadedNumberUtil.FloatOrByte(1f, (byte) 1));
+        cipEqu(-1f, new OverloadedNumberUtil.FloatOrByte(-1f, (byte) -1));
+        cipEqu(1.000009f, new OverloadedNumberUtil.FloatOrByte(1.000009f, 
(byte) 1));
+        cipEqu(-1.000009f, new OverloadedNumberUtil.FloatOrByte(-1.000009f, 
(byte) -1));
+        cipEqu(1.999991f, new OverloadedNumberUtil.FloatOrByte(1.999991f, 
(byte) 2));
+        cipEqu(-1.999991f, new OverloadedNumberUtil.FloatOrByte(-1.999991f, 
(byte) -2));
+        
+        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 
1000));
+        cipEqu(-1000f, new OverloadedNumberUtil.FloatOrShort(-1000f, (short) 
-1000));
+        cipEqu(1000.00006f);
+
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000));
+        cipEqu(-60000f, new OverloadedNumberUtil.FloatOrInteger(-60000f, 
-60000));
+        cipEqu(60000.004f);
+
+        cipEqu(100f, new OverloadedNumberUtil.FloatOrByte(100f, (byte) 100), 
TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 
1000), TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), 
TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), 
TypeFlags.LONG);
+        cipEqu((float) Integer.MAX_VALUE, (float) Integer.MAX_VALUE, 
TypeFlags.LONG);
+        cipEqu((float) -Integer.MAX_VALUE, (float) -Integer.MAX_VALUE);
+        
+        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE);
+    }
+    
+    public void testBigIntegerCoercion() {
+        BigInteger bi;
+        
+        cipEqu(BigInteger.ZERO, new 
OverloadedNumberUtil.BigIntegerOrByte(BigInteger.ZERO));
+        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
+        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
+        
+        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE + 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE - 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Short.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Short.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        
+        bi = new BigInteger(String.valueOf(Short.MAX_VALUE + 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Short.MIN_VALUE - 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        
+        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE + 1L));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE - 1L));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Long.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Long.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        
+        cipEqu(new 
BigInteger(String.valueOf(Long.MAX_VALUE)).add(BigInteger.ONE));
+        cipEqu(new 
BigInteger(String.valueOf(Long.MIN_VALUE)).subtract(BigInteger.ONE));
+        
+        bi = new BigInteger("0");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.FLOAT);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi),
+                TypeFlags.DOUBLE);
+
+        bi = new BigInteger("16777215");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-16777215");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        
+        bi = new BigInteger("16777216");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-16777216");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        
+        bi = new BigInteger("16777217");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.FLOAT);
+        bi = new BigInteger("-16777217");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.FLOAT);
+        
+        bi = new BigInteger("9007199254740991");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740991");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740992");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740992");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), 
TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740993");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740993");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740994");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-9007199254740994");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+    }
+    
+    private void cipEqu(Number actualAndExpected) {
+        cipEqu(actualAndExpected, actualAndExpected, -1);
+    }
+    
+    private void cipEqu(Number actual, Number expected) {
+        cipEqu(actual, expected, -1);
+    }
+
+    private void cipEqu(Number actualAndExpected, int flags) {
+        cipEqu(actualAndExpected, actualAndExpected, flags);
+    }
+    
+    @SuppressWarnings("boxing")
+    private void cipEqu(Number actual, Number expected, int flags) {
+        Number res = OverloadedNumberUtil.addFallbackType(actual, flags);
+        assertEquals(expected.getClass(), res.getClass());
+        assertEquals(expected, res);
+        
+        // Some number types wrap the number with multiple types and equals() 
only compares one of them. So we try to
+        // catch any inconsistency:
+        assertEquals(expected.byteValue(), res.byteValue());
+        assertEquals(expected.shortValue(), res.shortValue());
+        assertEquals(expected.intValue(), res.intValue());
+        assertEquals(expected.longValue(), res.longValue());
+        assertEquals(expected.floatValue(), res.floatValue());
+        assertEquals(expected.doubleValue(), res.doubleValue());
+    }
+    
+    public void testGetArgumentConversionPrice() {
+        // Unknown number types:
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, Integer.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, RationalNumber.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, Float.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                Float.class, RationalNumber.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, RationalNumber.class));
+        
+        // Fully check some rows (not all of them; the code is generated 
anyways):
+
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Short.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Integer.class));
+        assertEquals(10004, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Long.class));
+        assertEquals(10005, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigInteger.class));
+        assertEquals(30006, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Float.class));
+        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Double.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigDecimal.class));
+        
+        assertEquals(45001, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Byte.class));
+        assertEquals(44002, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Short.class));
+        assertEquals(41003, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Integer.class));
+        assertEquals(41004, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Long.class));
+        assertEquals(40005, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigInteger.class));
+        assertEquals(33006, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Float.class));
+        assertEquals(32007, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Double.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigDecimal.class));
+        
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Short.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Integer.class));
+        assertEquals(21004, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Long.class));
+        assertEquals(21005, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigInteger.class));
+        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Float.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Double.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
+        
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Short.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Integer.class));
+        assertEquals(Integer.MAX_VALUE, 
OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Long.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, 
BigInteger.class));
+        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Float.class));
+        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Double.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, 
BigDecimal.class));
+        
+        // Check if all fromC is present:
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Byte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Short.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Long.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Float.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Double.class, BigDecimal.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigDecimal.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.IntegerBigDecimal.class, 
BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrFloat.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrShort.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrShort.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrIntegerOrFloat.class, 
BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrByte.class, 
BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrShort.class, 
BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrInteger.class, 
BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrLong.class, 
BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrFloat.class, 
BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, 
BigDecimal.class));
+    }
+    
+}

Reply via email to