freemarker-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ddek...@apache.org
Subject [08/20] incubator-freemarker git commit: Removed BeansWrapper, merging it into DefaultObjectWrapper (the o.a.f.core.model.impl.beans packageis gone now). It works, but there's a lot of unused classes and logic now, which will have to be removed.
Date Tue, 28 Feb 2017 22:57:42 GMT
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/core/model/impl/beans/_MethodUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/model/impl/beans/_MethodUtil.java b/src/main/java/org/apache/freemarker/core/model/impl/beans/_MethodUtil.java
deleted file mode 100644
index f06f1f9..0000000
--- a/src/main/java/org/apache/freemarker/core/model/impl/beans/_MethodUtil.java
+++ /dev/null
@@ -1,293 +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.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.freemarker.core._DelayedConversionToString;
-import org.apache.freemarker.core._DelayedJQuote;
-import org.apache.freemarker.core._TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util.BugException;
-import org.apache.freemarker.core.util._ClassUtil;
-
-/**
- * For internal use only; don't depend on this, there's no backward compatibility guarantee at all!
- */
-public final class _MethodUtil {
-    
-    private _MethodUtil() {
-        // Not meant to be instantiated
-    }
-
-    /**
-     * Determines whether the type given as the 1st argument is convertible to the type given as the 2nd argument
-     * for method call argument conversion. This follows the rules of the Java reflection-based method call, except
-     * that since we don't have the value here, a boxed class is never seen as convertible to a primitive type. 
-     * 
-     * @return 0 means {@code false}, non-0 means {@code true}.
-     *         That is, 0 is returned less specificity or incomparable specificity, also when if
-     *         then method was aborted because of {@code ifHigherThan}.
-     *         The absolute value of the returned non-0 number symbolizes how more specific it is:
-     *         <ul>
-     *           <li>1: The two classes are identical</li>
-     *           <li>2: The 1st type is primitive, the 2nd type is the corresponding boxing class</li>
-     *           <li>3: Both classes are numerical, and one is convertible into the other with widening conversion.
-     *                  E.g., {@code int} is convertible to {@code long} and {#code double}, hence {@code int} is more
-     *                  specific.
-     *                  This ignores primitive VS boxed mismatches, except that a boxed class is never seen as
-     *                  convertible to a primitive class.</li>
-     *           <li>4: One class is {@code instanceof} of the other, but they aren't identical.
-     *               But unlike in Java, primitive numerical types are {@code instanceof} {@link Number} here.</li>
-     *         </ul> 
-     */
-    // TODO Seems that we don't use the full functionality of this anymore, so we could simplify this. See usages.
-    public static int isMoreOrSameSpecificParameterType(final Class specific, final Class generic, boolean bugfixed,
-            int ifHigherThan) {
-        if (ifHigherThan >= 4) return 0;
-        if (generic.isAssignableFrom(specific)) {
-            // Identity or widening reference conversion:
-            return generic == specific ? 1 : 4;
-        } else {
-            final boolean specificIsPrim = specific.isPrimitive(); 
-            final boolean genericIsPrim = generic.isPrimitive();
-            if (specificIsPrim) {
-                if (genericIsPrim) {
-                    if (ifHigherThan >= 3) return 0;
-                    return isWideningPrimitiveNumberConversion(specific, generic) ? 3 : 0;
-                } else {  // => specificIsPrim && !genericIsPrim
-                    if (bugfixed) {
-                        final Class specificAsBoxed = _ClassUtil.primitiveClassToBoxingClass(specific);
-                        if (specificAsBoxed == generic) {
-                            // A primitive class is more specific than its boxing class, because it can't store null
-                            return 2;
-                        } else if (generic.isAssignableFrom(specificAsBoxed)) {
-                            // Note: This only occurs if `specific` is a primitive numerical, and `generic == Number`
-                            return 4;
-                        } else if (ifHigherThan >= 3) {
-                            return 0;
-                        } else if (Number.class.isAssignableFrom(specificAsBoxed)
-                                && Number.class.isAssignableFrom(generic)) {
-                            return isWideningBoxedNumberConversion(specificAsBoxed, generic) ? 3 : 0;
-                        } else {
-                            return 0;
-                        }
-                    } else {
-                        return 0;
-                    }
-                }
-            } else {  // => !specificIsPrim
-                if (ifHigherThan >= 3) return 0;
-                if (bugfixed && !genericIsPrim
-                        && Number.class.isAssignableFrom(specific) && Number.class.isAssignableFrom(generic)) {
-                    return isWideningBoxedNumberConversion(specific, generic) ? 3 : 0;
-                } else {
-                    return 0;
-                }
-            }
-        }  // of: !generic.isAssignableFrom(specific) 
-    }
-
-    private static boolean isWideningPrimitiveNumberConversion(final Class source, final Class target) {
-        if (target == Short.TYPE && (source == Byte.TYPE)) {
-            return true;
-        } else if (target == Integer.TYPE && 
-           (source == Short.TYPE || source == Byte.TYPE)) {
-            return true;
-        } else if (target == Long.TYPE && 
-           (source == Integer.TYPE || source == Short.TYPE || 
-            source == Byte.TYPE)) {
-            return true;
-        } else if (target == Float.TYPE && 
-           (source == Long.TYPE || source == Integer.TYPE || 
-            source == Short.TYPE || source == Byte.TYPE)) {
-            return true;
-        } else if (target == Double.TYPE && 
-           (source == Float.TYPE || source == Long.TYPE || 
-            source == Integer.TYPE || source == Short.TYPE || 
-            source == Byte.TYPE)) {
-            return true; 
-        } else {
-            return false;
-        }
-    }
-
-    private static boolean isWideningBoxedNumberConversion(final Class source, final Class target) {
-        if (target == Short.class && source == Byte.class) {
-            return true;
-        } else if (target == Integer.class && 
-           (source == Short.class || source == Byte.class)) {
-            return true;
-        } else if (target == Long.class && 
-           (source == Integer.class || source == Short.class || 
-            source == Byte.class)) {
-            return true;
-        } else if (target == Float.class && 
-           (source == Long.class || source == Integer.class || 
-            source == Short.class || source == Byte.class)) {
-            return true;
-        } else if (target == Double.class && 
-           (source == Float.class || source == Long.class || 
-            source == Integer.class || source == Short.class || 
-            source == Byte.class)) {
-            return true; 
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Attention, this doesn't handle primitive classes correctly, nor numerical conversions.
-     */
-    public static Set getAssignables(Class c1, Class c2) {
-        Set s = new HashSet();
-        collectAssignables(c1, c2, s);
-        return s;
-    }
-    
-    private static void collectAssignables(Class c1, Class c2, Set s) {
-        if (c1.isAssignableFrom(c2)) {
-            s.add(c1);
-        }
-        Class sc = c1.getSuperclass();
-        if (sc != null) {
-            collectAssignables(sc, c2, s);
-        }
-        Class[] itf = c1.getInterfaces();
-        for (Class anItf : itf) {
-            collectAssignables(anItf, c2, s);
-        }
-    }
-
-    public static Class[] getParameterTypes(Member member) {
-        if (member instanceof Method) {
-            return ((Method) member).getParameterTypes();
-        }
-        if (member instanceof Constructor) {
-            return ((Constructor) member).getParameterTypes();
-        }
-        throw new IllegalArgumentException("\"member\" must be Method or Constructor");
-    }
-
-    public static boolean isVarargs(Member member) {
-        if (member instanceof Method) { 
-            return ((Method) member).isVarArgs();
-        }
-        if (member instanceof Constructor) {
-            return ((Constructor) member).isVarArgs();
-        }
-        throw new BugException();
-    }
-
-    /**
-     * Returns a more streamlined method or constructor description than {@code Member.toString()} does.
-     */
-    public static String toString(Member member) {
-        if (!(member instanceof Method || member instanceof Constructor)) {
-            throw new IllegalArgumentException("\"member\" must be a Method or Constructor");
-        }
-        
-        StringBuilder sb = new StringBuilder();
-        
-        if ((member.getModifiers() & Modifier.STATIC) != 0) {
-            sb.append("static ");
-        }
-        
-        String className = _ClassUtil.getShortClassName(member.getDeclaringClass());
-        if (className != null) {
-            sb.append(className);
-            sb.append('.');
-        }
-        sb.append(member.getName());
-
-        sb.append('(');
-        Class[] paramTypes = _MethodUtil.getParameterTypes(member);
-        for (int i = 0; i < paramTypes.length; i++) {
-            if (i != 0) sb.append(", ");
-            String paramTypeDecl = _ClassUtil.getShortClassName(paramTypes[i]);
-            if (i == paramTypes.length - 1 && paramTypeDecl.endsWith("[]") && _MethodUtil.isVarargs(member)) {
-                sb.append(paramTypeDecl.substring(0, paramTypeDecl.length() - 2));
-                sb.append("...");
-            } else {
-                sb.append(paramTypeDecl);
-            }
-        }
-        sb.append(')');
-        
-        return sb.toString();
-    }
-
-    public static Object[] invocationErrorMessageStart(Member member) {
-        return invocationErrorMessageStart(member, member instanceof Constructor);
-    }
-    
-    private static Object[] invocationErrorMessageStart(Object member, boolean isConstructor) {
-        return new Object[] { "Java ", isConstructor ? "constructor " : "method ", new _DelayedJQuote(member) };
-    }
-
-    public static TemplateModelException newInvocationTemplateModelException(Object object, Member member, Throwable e) {
-        return newInvocationTemplateModelException(
-                object,
-                member,
-                (member.getModifiers() & Modifier.STATIC) != 0,
-                member instanceof Constructor,
-                e);
-    }
-
-    public static TemplateModelException newInvocationTemplateModelException(Object object, CallableMemberDescriptor callableMemberDescriptor, Throwable e) {
-        return newInvocationTemplateModelException(
-                object,
-                new _DelayedConversionToString(callableMemberDescriptor) {
-                    @Override
-                    protected String doConversion(Object callableMemberDescriptor) {
-                        return ((CallableMemberDescriptor) callableMemberDescriptor).getDeclaration();
-                    }
-                },
-                callableMemberDescriptor.isStatic(),
-                callableMemberDescriptor.isConstructor(),
-                e);
-    }
-    
-    private static TemplateModelException newInvocationTemplateModelException(
-            Object parentObject, Object member, boolean isStatic, boolean isConstructor, Throwable e) {
-        while (e instanceof InvocationTargetException) {
-            Throwable cause = ((InvocationTargetException) e).getTargetException();
-            if (cause != null) {
-                e = cause;
-            } else {
-                break;
-            }
-        }
-
-        return new _TemplateModelException(e,
-                invocationErrorMessageStart(member, isConstructor),
-                " threw an exception",
-                isStatic || isConstructor ? "" : new Object[] {
-                    " when invoked on ", parentObject.getClass(), " object ", new _DelayedJQuote(parentObject) 
-                },
-                "; see cause exception in the Java stack trace.");
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/core/model/impl/beans/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/model/impl/beans/package.html b/src/main/java/org/apache/freemarker/core/model/impl/beans/package.html
deleted file mode 100644
index bd6b36c..0000000
--- a/src/main/java/org/apache/freemarker/core/model/impl/beans/package.html
+++ /dev/null
@@ -1,39 +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.
--->
-<html>
-<head>
-<title></title>
-</head>
-<body>
-
-<p>The {@linkplain org.apache.freemarker.core.model.impl.DefaultObjectWrapper default object wrapper} of FreeMarker uses
-this to expose Java Beans and POJO-s to templates.</p>
-
-<p>Most of the issues dealing with beans are handled by the 
-{@link freemarker.ext.beans.BeansWrapper#wrap(Object)}and {@link 
-freemarker.ext.beans.BeansWrapper#getStaticModels()} methods. In normal cases, 
- these are the only methods
-you should use to turn an arbitrary Java object into a 
-FreeMarker {@link freemarker.template.TemplateModel}. Additionally, you can manually create 
-instance of any wrapper class using its constructors.
-Note, however that in such cases you bypass the eventual model caching
-of the wrapper.</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/core/model/impl/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/model/impl/package.html b/src/main/java/org/apache/freemarker/core/model/impl/package.html
new file mode 100644
index 0000000..100c5c5
--- /dev/null
+++ b/src/main/java/org/apache/freemarker/core/model/impl/package.html
@@ -0,0 +1,39 @@
+<!--
+  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.
+-->
+<html>
+<head>
+<title></title>
+</head>
+<body>
+
+<p>The {@linkplain org.apache.freemarker.core.model.impl.DefaultObjectWrapper default object wrapper} of FreeMarker uses
+this to expose Java Beans and POJO-s to templates.</p>
+
+<p>Most of the issues dealing with beans are handled by the 
+{@link freemarker.ext.beans.DefaultObjectWrapper#wrap(Object)}and {@link
+freemarker.ext.beans.DefaultObjectWrapper#getStaticModels()} methods. In normal cases,
+ these are the only methods
+you should use to turn an arbitrary Java object into a 
+FreeMarker {@link freemarker.template.TemplateModel}. Additionally, you can manually create 
+instance of any wrapper class using its constructors.
+Note, however that in such cases you bypass the eventual model caching
+of the wrapper.</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/util/FTLUtil.java b/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
index 9f0cca7..eba25f6 100644
--- a/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
+++ b/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
@@ -43,17 +43,17 @@ import org.apache.freemarker.core.model.TemplateScalarModel;
 import org.apache.freemarker.core.model.TemplateSequenceModel;
 import org.apache.freemarker.core.model.TemplateTransformModel;
 import org.apache.freemarker.core.model.WrapperTemplateModel;
-import org.apache.freemarker.core.model.impl.beans.BeanModel;
-import org.apache.freemarker.core.model.impl.beans.BooleanModel;
-import org.apache.freemarker.core.model.impl.beans.CollectionModel;
-import org.apache.freemarker.core.model.impl.beans.DateModel;
-import org.apache.freemarker.core.model.impl.beans.EnumerationModel;
-import org.apache.freemarker.core.model.impl.beans.IteratorModel;
-import org.apache.freemarker.core.model.impl.beans.MapModel;
-import org.apache.freemarker.core.model.impl.beans.NumberModel;
-import org.apache.freemarker.core.model.impl.beans.OverloadedMethodsModel;
-import org.apache.freemarker.core.model.impl.beans.SimpleMethodModel;
-import org.apache.freemarker.core.model.impl.beans.StringModel;
+import org.apache.freemarker.core.model.impl.BeanModel;
+import org.apache.freemarker.core.model.impl.BooleanModel;
+import org.apache.freemarker.core.model.impl.CollectionModel;
+import org.apache.freemarker.core.model.impl.DateModel;
+import org.apache.freemarker.core.model.impl.EnumerationModel;
+import org.apache.freemarker.core.model.impl.IteratorModel;
+import org.apache.freemarker.core.model.impl.MapModel;
+import org.apache.freemarker.core.model.impl.NumberModel;
+import org.apache.freemarker.core.model.impl.OverloadedMethodsModel;
+import org.apache.freemarker.core.model.impl.SimpleMethodModel;
+import org.apache.freemarker.core.model.impl.StringModel;
 
 /**
  * Static utility methods that perform tasks specific to the FreeMarker Template Language (FTL).

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/core/util/_ClassUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/util/_ClassUtil.java b/src/main/java/org/apache/freemarker/core/util/_ClassUtil.java
index 0401ce0..f97d186 100644
--- a/src/main/java/org/apache/freemarker/core/util/_ClassUtil.java
+++ b/src/main/java/org/apache/freemarker/core/util/_ClassUtil.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core.util;
 
-import org.apache.freemarker.core.model.impl.beans.NumberModel;
+import org.apache.freemarker.core.model.impl.NumberModel;
 
 public class _ClassUtil {
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
index 25d09e5..0016241 100644
--- a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
+++ b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
@@ -411,7 +411,6 @@ public class FreemarkerServlet extends HttpServlet {
     private static final String DEPR_INITPARAM_ENCODING = "DefaultEncoding";
     private static final String DEPR_INITPARAM_OBJECT_WRAPPER = "ObjectWrapper";
     private static final String DEPR_INITPARAM_WRAPPER_SIMPLE = "simple";
-    private static final String DEPR_INITPARAM_WRAPPER_BEANS = "beans";
     private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER = "TemplateExceptionHandler";
     private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW = "rethrow";
     private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG = "debug";
@@ -1298,9 +1297,6 @@ public class FreemarkerServlet extends HttpServlet {
                         + Configurable.OBJECT_WRAPPER_KEY + " and "
                         + DEPR_INITPARAM_OBJECT_WRAPPER);
             }
-            if (DEPR_INITPARAM_WRAPPER_BEANS.equals(wrapper)) {
-                return _StaticObjectWrappers.BEANS_WRAPPER;
-            }
             if (DEPR_INITPARAM_WRAPPER_SIMPLE.equals(wrapper)) {
                 return _StaticObjectWrappers.SIMPLE_OBJECT_WRAPPER;
             }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java b/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java
index 956064a..e9e9bf4 100644
--- a/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java
+++ b/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java
@@ -33,7 +33,7 @@ import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateSequenceModel;
 import org.apache.freemarker.core.model.TemplateTransformModel;
-import org.apache.freemarker.core.model.impl.beans.SimpleMethodModel;
+import org.apache.freemarker.core.model.impl.SimpleMethodModel;
 import org.apache.freemarker.core.util.BugException;
 import org.apache.freemarker.core.util._ClassUtil;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/servlet/jsp/JspContextModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/jsp/JspContextModel.java b/src/main/java/org/apache/freemarker/servlet/jsp/JspContextModel.java
index dcd7fcd..d07796c 100644
--- a/src/main/java/org/apache/freemarker/servlet/jsp/JspContextModel.java
+++ b/src/main/java/org/apache/freemarker/servlet/jsp/JspContextModel.java
@@ -46,7 +46,7 @@ implements
     @Override
     public TemplateModel get(String key) throws TemplateModelException {
         Object bean = scope == ANY_SCOPE ? pageContext.findAttribute(key) : pageContext.getAttribute(key, scope);
-        return _StaticObjectWrappers.BEANS_WRAPPER.wrap(bean);
+        return _StaticObjectWrappers.DEFAULT_OBJECT_WRAPPER.wrap(bean);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java b/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
index 4711cd2..526d3d5 100644
--- a/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
+++ b/src/main/java/org/apache/freemarker/servlet/jsp/JspTagModelBase.java
@@ -40,7 +40,7 @@ import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.impl._StaticObjectWrappers;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.util._StringUtil;
 import org.apache.freemarker.servlet.jsp.SimpleTagDirectiveModel.TemplateExceptionWrapperJspException;
 
@@ -84,7 +84,7 @@ class JspTagModelBase {
         if (args != null && !args.isEmpty()) {
             ObjectWrapperAndUnwrapper unwrapper = 
                     wrapper instanceof ObjectWrapperAndUnwrapper ? (ObjectWrapperAndUnwrapper) wrapper
-                            : _StaticObjectWrappers.BEANS_WRAPPER;  // [2.4] Throw exception in this case
+                            : _StaticObjectWrappers.DEFAULT_OBJECT_WRAPPER;  // [2.4] Throw exception in this case
             final Object[] argArray = new Object[1];
             for (Iterator iter = args.entrySet().iterator(); iter.hasNext(); ) {
                 final Map.Entry entry = (Map.Entry) iter.next();
@@ -102,7 +102,7 @@ class JspTagModelBase {
                     }
                 } else {
                     if (arg instanceof BigDecimal) {
-                        argArray[0] = BeansWrapper.coerceBigDecimal(
+                        argArray[0] = DefaultObjectWrapper.coerceBigDecimal(
                                 (BigDecimal) arg, setterMethod.getParameterTypes()[0]);
                     }
                     try {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java b/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
index 930223c..67b336e 100644
--- a/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
+++ b/src/main/java/org/apache/freemarker/servlet/jsp/TaglibFactory.java
@@ -68,7 +68,6 @@ import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateTransformModel;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
 import org.apache.freemarker.core.util.BugException;
 import org.apache.freemarker.core.util._ClassUtil;
 import org.apache.freemarker.core.util._NullArgumentException;
@@ -306,7 +305,7 @@ public class TaglibFactory implements TemplateHashModel {
      * Sets the {@link ObjectWrapper} used when building the JSP tag library {@link TemplateHashModel}-s from the TLD-s.
      * Usually, it should be the same {@link ObjectWrapper} that will be used inside the templates. {@code null} value
      * is only supported for backward compatibility. For custom EL functions to be exposed, it must be non-{@code null}
-     * and an {@code intanceof} {@link BeansWrapper} (like typically, a {@link DefaultObjectWrapper}).
+     * and an {@code intanceof} {@link DefaultObjectWrapper} (like typically, a {@link DefaultObjectWrapper}).
      * 
      * @since 2.3.22
      */
@@ -1624,7 +1623,7 @@ public class TaglibFactory implements TemplateHashModel {
         private static final String E_LISTENER = "listener";
         private static final String E_LISTENER_CLASS = "listener-class";
 
-        private final BeansWrapper beansWrapper;
+        private final DefaultObjectWrapper defaultObjectWrapper;
 
         private final Map<String, TemplateModel> tagsAndFunctions = new HashMap<>();
         private final List listeners = new ArrayList();
@@ -1642,16 +1641,16 @@ public class TaglibFactory implements TemplateHashModel {
         private String listenerClassCData;
 
         TldParserForTaglibBuilding(ObjectWrapper wrapper) {
-            if (wrapper instanceof BeansWrapper) {
-                beansWrapper = (BeansWrapper) wrapper;
+            if (wrapper instanceof DefaultObjectWrapper) {
+                defaultObjectWrapper = (DefaultObjectWrapper) wrapper;
             } else {
-                beansWrapper = null;
+                defaultObjectWrapper = null;
                 if (LOG.isWarnEnabled()) {
                     LOG.warn("Custom EL functions won't be loaded because "
                             + (wrapper == null
                                     ? "no ObjectWrapper was specified for the TaglibFactory "
                                             + "(via TaglibFactory.setObjectWrapper(...), exists since 2.3.22)"
-                                    : "the ObjectWrapper wasn't instance of " + BeansWrapper.class.getName())
+                                    : "the ObjectWrapper wasn't instance of " + DefaultObjectWrapper.class.getName())
                             + ".");
                 }
             }
@@ -1747,7 +1746,7 @@ public class TaglibFactory implements TemplateHashModel {
 
                     tagNameCData = null;
                     tagClassCData = null;
-                } else if (E_FUNCTION.equals(qName) && beansWrapper != null) {
+                } else if (E_FUNCTION.equals(qName) && defaultObjectWrapper != null) {
                     checkChildElementNotNull(qName, E_FUNCTION_CLASS, functionClassCData);
                     checkChildElementNotNull(qName, E_FUNCTION_SIGNATURE, functionSignatureCData);
                     checkChildElementNotNull(qName, E_NAME, functionNameCData);
@@ -1777,7 +1776,7 @@ public class TaglibFactory implements TemplateHashModel {
 
                     final TemplateMethodModelEx elFunctionModel;
                     try {
-                        elFunctionModel = beansWrapper.wrap(null, functionMethod);
+                        elFunctionModel = defaultObjectWrapper.wrap(null, functionMethod);
                     } catch (Exception e) {
                         throw new TldParsingSAXException(
                                 "FreeMarker object wrapping failed on method : " + functionMethod,

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/resources/org/apache/freemarker/core/model/impl/beans/unsafeMethods.properties
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/freemarker/core/model/impl/beans/unsafeMethods.properties b/src/main/resources/org/apache/freemarker/core/model/impl/beans/unsafeMethods.properties
deleted file mode 100644
index f1f4e18..0000000
--- a/src/main/resources/org/apache/freemarker/core/model/impl/beans/unsafeMethods.properties
+++ /dev/null
@@ -1,98 +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.
-
-java.lang.Object.wait()
-java.lang.Object.wait(long)
-java.lang.Object.wait(long,int)
-java.lang.Object.notify()
-java.lang.Object.notifyAll()
-
-java.lang.Class.getClassLoader()
-java.lang.Class.newInstance()
-java.lang.Class.forName(java.lang.String)
-java.lang.Class.forName(java.lang.String,boolean,java.lang.ClassLoader)
-
-java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;)
-
-java.lang.reflect.Method.invoke(java.lang.Object,[Ljava.lang.Object;)
-
-java.lang.reflect.Field.set(java.lang.Object,java.lang.Object)
-java.lang.reflect.Field.setBoolean(java.lang.Object,boolean)
-java.lang.reflect.Field.setByte(java.lang.Object,byte)
-java.lang.reflect.Field.setChar(java.lang.Object,char)
-java.lang.reflect.Field.setDouble(java.lang.Object,double)
-java.lang.reflect.Field.setFloat(java.lang.Object,float)
-java.lang.reflect.Field.setInt(java.lang.Object,int)
-java.lang.reflect.Field.setLong(java.lang.Object,long)
-java.lang.reflect.Field.setShort(java.lang.Object,short)
-
-java.lang.reflect.AccessibleObject.setAccessible([Ljava.lang.reflect.AccessibleObject;,boolean)
-java.lang.reflect.AccessibleObject.setAccessible(boolean)
-
-java.lang.Thread.destroy()
-java.lang.Thread.getContextClassLoader()
-java.lang.Thread.interrupt()
-java.lang.Thread.join()
-java.lang.Thread.join(long)
-java.lang.Thread.join(long,int)
-java.lang.Thread.resume()
-java.lang.Thread.run()
-java.lang.Thread.setContextClassLoader(java.lang.ClassLoader)
-java.lang.Thread.setDaemon(boolean)
-java.lang.Thread.setName(java.lang.String)
-java.lang.Thread.setPriority(int)
-java.lang.Thread.sleep(long)
-java.lang.Thread.sleep(long,int)
-java.lang.Thread.start()
-java.lang.Thread.stop()
-java.lang.Thread.stop(java.lang.Throwable)
-java.lang.Thread.suspend()
-
-java.lang.ThreadGroup.allowThreadSuspension(boolean)
-java.lang.ThreadGroup.destroy()
-java.lang.ThreadGroup.interrupt()
-java.lang.ThreadGroup.resume()
-java.lang.ThreadGroup.setDaemon(boolean)
-java.lang.ThreadGroup.setMaxPriority(int)
-java.lang.ThreadGroup.stop()
-java.lang.Thread.suspend()
-
-java.lang.Runtime.addShutdownHook(java.lang.Thread)
-java.lang.Runtime.exec(java.lang.String)
-java.lang.Runtime.exec([Ljava.lang.String;)
-java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;)
-java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;,java.io.File)
-java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;)
-java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;,java.io.File)
-java.lang.Runtime.exit(int)
-java.lang.Runtime.halt(int)
-java.lang.Runtime.load(java.lang.String)
-java.lang.Runtime.loadLibrary(java.lang.String)
-java.lang.Runtime.removeShutdownHook(java.lang.Thread)
-java.lang.Runtime.traceInstructions(boolean)
-java.lang.Runtime.traceMethodCalls(boolean)
-
-java.lang.System.exit(int)
-java.lang.System.load(java.lang.String)
-java.lang.System.loadLibrary(java.lang.String)
-java.lang.System.runFinalizersOnExit(boolean)
-java.lang.System.setErr(java.io.PrintStream)
-java.lang.System.setIn(java.io.InputStream)
-java.lang.System.setOut(java.io.PrintStream)
-java.lang.System.setProperties(java.util.Properties)
-java.lang.System.setProperty(java.lang.String,java.lang.String)
-java.lang.System.setSecurityManager(java.lang.SecurityManager)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/main/resources/org/apache/freemarker/core/model/impl/unsafeMethods.properties
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/freemarker/core/model/impl/unsafeMethods.properties b/src/main/resources/org/apache/freemarker/core/model/impl/unsafeMethods.properties
new file mode 100644
index 0000000..f1f4e18
--- /dev/null
+++ b/src/main/resources/org/apache/freemarker/core/model/impl/unsafeMethods.properties
@@ -0,0 +1,98 @@
+# 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.
+
+java.lang.Object.wait()
+java.lang.Object.wait(long)
+java.lang.Object.wait(long,int)
+java.lang.Object.notify()
+java.lang.Object.notifyAll()
+
+java.lang.Class.getClassLoader()
+java.lang.Class.newInstance()
+java.lang.Class.forName(java.lang.String)
+java.lang.Class.forName(java.lang.String,boolean,java.lang.ClassLoader)
+
+java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;)
+
+java.lang.reflect.Method.invoke(java.lang.Object,[Ljava.lang.Object;)
+
+java.lang.reflect.Field.set(java.lang.Object,java.lang.Object)
+java.lang.reflect.Field.setBoolean(java.lang.Object,boolean)
+java.lang.reflect.Field.setByte(java.lang.Object,byte)
+java.lang.reflect.Field.setChar(java.lang.Object,char)
+java.lang.reflect.Field.setDouble(java.lang.Object,double)
+java.lang.reflect.Field.setFloat(java.lang.Object,float)
+java.lang.reflect.Field.setInt(java.lang.Object,int)
+java.lang.reflect.Field.setLong(java.lang.Object,long)
+java.lang.reflect.Field.setShort(java.lang.Object,short)
+
+java.lang.reflect.AccessibleObject.setAccessible([Ljava.lang.reflect.AccessibleObject;,boolean)
+java.lang.reflect.AccessibleObject.setAccessible(boolean)
+
+java.lang.Thread.destroy()
+java.lang.Thread.getContextClassLoader()
+java.lang.Thread.interrupt()
+java.lang.Thread.join()
+java.lang.Thread.join(long)
+java.lang.Thread.join(long,int)
+java.lang.Thread.resume()
+java.lang.Thread.run()
+java.lang.Thread.setContextClassLoader(java.lang.ClassLoader)
+java.lang.Thread.setDaemon(boolean)
+java.lang.Thread.setName(java.lang.String)
+java.lang.Thread.setPriority(int)
+java.lang.Thread.sleep(long)
+java.lang.Thread.sleep(long,int)
+java.lang.Thread.start()
+java.lang.Thread.stop()
+java.lang.Thread.stop(java.lang.Throwable)
+java.lang.Thread.suspend()
+
+java.lang.ThreadGroup.allowThreadSuspension(boolean)
+java.lang.ThreadGroup.destroy()
+java.lang.ThreadGroup.interrupt()
+java.lang.ThreadGroup.resume()
+java.lang.ThreadGroup.setDaemon(boolean)
+java.lang.ThreadGroup.setMaxPriority(int)
+java.lang.ThreadGroup.stop()
+java.lang.Thread.suspend()
+
+java.lang.Runtime.addShutdownHook(java.lang.Thread)
+java.lang.Runtime.exec(java.lang.String)
+java.lang.Runtime.exec([Ljava.lang.String;)
+java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;)
+java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;,java.io.File)
+java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;)
+java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;,java.io.File)
+java.lang.Runtime.exit(int)
+java.lang.Runtime.halt(int)
+java.lang.Runtime.load(java.lang.String)
+java.lang.Runtime.loadLibrary(java.lang.String)
+java.lang.Runtime.removeShutdownHook(java.lang.Thread)
+java.lang.Runtime.traceInstructions(boolean)
+java.lang.Runtime.traceMethodCalls(boolean)
+
+java.lang.System.exit(int)
+java.lang.System.load(java.lang.String)
+java.lang.System.loadLibrary(java.lang.String)
+java.lang.System.runFinalizersOnExit(boolean)
+java.lang.System.setErr(java.io.PrintStream)
+java.lang.System.setIn(java.io.InputStream)
+java.lang.System.setOut(java.io.PrintStream)
+java.lang.System.setProperties(java.util.Properties)
+java.lang.System.setProperty(java.lang.String,java.lang.String)
+java.lang.System.setSecurityManager(java.lang.SecurityManager)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/manual/en_US/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/src/manual/en_US/FM3-CHANGE-LOG.txt b/src/manual/en_US/FM3-CHANGE-LOG.txt
index 9486c33..72498a6 100644
--- a/src/manual/en_US/FM3-CHANGE-LOG.txt
+++ b/src/manual/en_US/FM3-CHANGE-LOG.txt
@@ -73,9 +73,7 @@ the FreeMarer 3 changelog here:
   OutputFormat realted classes were moved to org.apache.freemarker.core.outputformat.
   ValueFormat related classes were moved to org.apache.freemarker.core.valueformat.
   ArithmeticEngine related classes were moved to org.apache.freemarker.core.arithmetic.
-  freemarker.ext.beans were moved under org.apache.freemarker.core.model.impl.beans for now (but later
-  we only want a DefaultObject wrapper, no BeansWrapper, so this will change) and freemarker.ext.dom
-  was moved to org.apache.freemarker.dom.
+  freemarker.ext.dom was moved into org.apache.freemarker.dom.
 - Moved the all the static final ObjectWrapper-s to the new _StaticObjectWrappers class, and made them
   write protected (non-configurable). Also now they come from the pool that ObjectWrapper builders use.
 - WrappingTemplateModel.objectWrapper is now final, and its statically stored default value can't be set anymore.
@@ -119,4 +117,4 @@ the FreeMarer 3 changelog here:
   Also, on the places where ParseException was used for other than template   parsing, o.a.f.core.util.GenericParseException is used now instead,
   which doesn't have the template parsing related fields that we can't fill.
 - Removed DefaultObjectWrapper settings that only exist so that you can set backward compatible behavior instead of the
-  recommended value: useAdaptersForContainers, forceLegacyNonListCollections, iterableSupport
\ No newline at end of file
+  recommended value: useAdaptersForContainers, forceLegacyNonListCollections, iterableSupport, simpleMapWrapper
\ 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/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
index 8413770..ee4bcbd 100644
--- a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -42,10 +42,9 @@ import org.apache.freemarker.core.Configurable.UnknownSettingException;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateScalarModel;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapperBuilder;
 import org.apache.freemarker.core.model.impl.SimpleScalar;
 import org.apache.freemarker.core.model.impl._StaticObjectWrappers;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapperBuilder;
-import org.apache.freemarker.core.model.impl.beans.StringModel;
 import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
 import org.apache.freemarker.core.outputformat.OutputFormat;
 import org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
@@ -1081,12 +1080,12 @@ public class ConfigurationTest extends TestCase {
         cfg.setSharedVariable("b", "bbLegacy");
         
         // Cause re-wrapping of variables added via setSharedVaribles:
-        cfg.setObjectWrapper(new BeansWrapperBuilder(Configuration.VERSION_3_0_0).build());
+        cfg.setObjectWrapper(new DefaultObjectWrapperBuilder(Configuration.VERSION_3_0_0).build());
 
         {
             TemplateScalarModel aVal = (TemplateScalarModel) cfg.getSharedVariable("a");
             assertEquals("aa", aVal.getAsString());
-            assertEquals(StringModel.class, aVal.getClass());
+            assertEquals(SimpleScalar.class, aVal.getClass());
             
             TemplateScalarModel bVal = (TemplateScalarModel) cfg.getSharedVariable("b");
             assertEquals("bbLegacy", bVal.getAsString());

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java b/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
index 224ff7d..aa9e66b 100644
--- a/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
+++ b/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
@@ -23,52 +23,37 @@ import java.util.Iterator;
 
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapperBuilder;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapperBuilder;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Test;
 
 public class IteratorIssuesTest extends TemplateTest {
-    
+
+    private static final DefaultObjectWrapper OW = new DefaultObjectWrapperBuilder(Configuration.VERSION_3_0_0).build();
+
     private static final String FTL_HAS_CONTENT_AND_LIST
             = "<#if it?hasContent><#list it as i>${i}</#list><#else>empty</#if>";
     private static final String OUT_HAS_CONTENT_AND_LIST_ABC = "abc";
     private static final String OUT_HAS_CONTENT_AND_LIST_EMPTY = "empty";
-    
+
     private static final String FTL_LIST_AND_HAS_CONTENT
             = "<#list it as i>${i}${it?hasContent?then('+', '-')}</#list>";
     private static final String OUT_LIST_AND_HAS_CONTENT_BW_GOOD = "a+b+c-";
 
     @Test
-    public void testHasContentAndListDOW() throws Exception {
-        addToDataModel("it", getDOW300().wrap(getAbcIt()));
+    public void testHasContentAndList() throws Exception {
+        addToDataModel("it", OW.wrap(getAbcIt()));
         assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_ABC);
-        
-        addToDataModel("it", getDOW300().wrap(getEmptyIt()));
-        assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_EMPTY);
-    }
 
-    @Test
-    public void testHasContentAndListBW() throws Exception {
-        addToDataModel("it", getBW300().wrap(getAbcIt()));
-        assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_ABC);
-        
-        addToDataModel("it", getBW300().wrap(getEmptyIt()));
+        addToDataModel("it", OW.wrap(getEmptyIt()));
         assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_EMPTY);
     }
-    
+
     @Test
-    public void testListAndHasContentDOW() throws Exception {
-        addToDataModel("it", getDOW300().wrap(getAbcIt()));
+    public void testListAndHasContent() throws Exception {
+        addToDataModel("it", OW.wrap(getAbcIt()));
         assertErrorContains(FTL_LIST_AND_HAS_CONTENT, "can be listed only once");
     }
 
-    @Test
-    public void testListAndHasContentBW() throws Exception {
-        addToDataModel("it", getBW300().wrap(getAbcIt()));
-        assertOutput(FTL_LIST_AND_HAS_CONTENT, OUT_LIST_AND_HAS_CONTENT_BW_GOOD);
-    }
-    
     private Iterator getAbcIt() {
         return Arrays.asList(new String[] { "a", "b", "c" }).iterator();
     }
@@ -76,13 +61,5 @@ public class IteratorIssuesTest extends TemplateTest {
     private Iterator getEmptyIt() {
         return Arrays.asList(new String[] {  }).iterator();
     }
-    
-    private DefaultObjectWrapper getDOW300() {
-        return new DefaultObjectWrapperBuilder(Configuration.VERSION_3_0_0).build();
-    }
 
-    private BeansWrapper getBW300() {
-        return new BeansWrapperBuilder(Configuration.VERSION_3_0_0).build();
-    }
-    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java b/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
index 5a702d4..ce91c66 100644
--- a/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
+++ b/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
@@ -42,7 +42,6 @@ import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
 import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
 import org.apache.freemarker.core.templateresolver.CacheStorage;
 import org.apache.freemarker.core.templateresolver.TemplateLoader;
 import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
@@ -359,24 +358,23 @@ public class ObjectBuilderSettingsTest {
             assertNull(res.b4.b4);
         }
     }
-    
+
     @Test
-    public void beansWrapperTest() throws Exception {
-        BeansWrapper bw = (BeansWrapper) _ObjectBuilderSettingEvaluator.eval(
-                "BeansWrapper(3.0.0, simpleMapWrapper=true, exposeFields=true)",
+    public void defaultObjectWrapperTest() throws Exception {
+        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
+                "DefaultObjectWrapper(3.0.0)",
                 ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-        assertEquals(Configuration.VERSION_3_0_0, bw.getIncompatibleImprovements());
-        assertTrue(bw.isSimpleMapWrapper());
-        assertTrue(bw.isExposeFields());
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+        assertFalse(ow.isExposeFields());
     }
 
     @Test
-    public void defaultObjectWrapperTest() throws Exception {
-        DefaultObjectWrapper bw = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
-                "DefaultObjectWrapper(3.0.0)",
+    public void defaultObjectWrapperTest2() throws Exception {
+        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
+                "DefaultObjectWrapper(3.0.0, exposeFields=true)",
                 ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-        assertEquals(Configuration.VERSION_3_0_0, bw.getIncompatibleImprovements());
-        assertFalse(bw.isExposeFields());
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+        assertTrue(ow.isExposeFields());
     }
 
     @Test
@@ -386,7 +384,7 @@ public class ObjectBuilderSettingsTest {
         {
             Properties props = new Properties();
             props.setProperty(Configurable.OBJECT_WRAPPER_KEY,
-                    "org.apache.freemarker.core.model.impl.beans.BeansWrapper(3.0.0)");
+                    "org.apache.freemarker.core.model.impl.DefaultObjectWrapper(3.0.0)");
             props.setProperty(Configurable.ARITHMETIC_ENGINE_KEY,
                     "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyArithmeticEngine");
             props.setProperty(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY,
@@ -399,10 +397,10 @@ public class ObjectBuilderSettingsTest {
             props.setProperty(Configuration.TEMPLATE_LOADER_KEY,
                     "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateLoader()");
             cfg.setSettings(props);
-            assertEquals(BeansWrapper.class, cfg.getObjectWrapper().getClass());
+            assertEquals(DefaultObjectWrapper.class, cfg.getObjectWrapper().getClass());
             assertTrue(((WriteProtectable) cfg.getObjectWrapper()).isWriteProtected());
             assertEquals(
-                    Configuration.VERSION_3_0_0, ((BeansWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
+                    Configuration.VERSION_3_0_0, ((DefaultObjectWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
             assertEquals(DummyArithmeticEngine.class, cfg.getArithmeticEngine().getClass());
             assertEquals(DummyTemplateExceptionHandler.class, cfg.getTemplateExceptionHandler().getClass());
             assertEquals(DummyCacheStorage.class, cfg.getCacheStorage().getClass());
@@ -428,7 +426,7 @@ public class ObjectBuilderSettingsTest {
             assertEquals(1, ((DummyArithmeticEngine) cfg.getArithmeticEngine()).getX());
             assertEquals(1, ((DummyTemplateExceptionHandler) cfg.getTemplateExceptionHandler()).getX());
             assertEquals(Configuration.VERSION_3_0_0,
-                    ((BeansWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
+                    ((DefaultObjectWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
             assertEquals(500, ((MruCacheStorage) cfg.getCacheStorage()).getSoftSizeLimit());
             assertEquals(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER, cfg.getNewBuiltinClassResolver());
             assertEquals("utf-8", cfg.getDefaultEncoding());
@@ -436,16 +434,16 @@ public class ObjectBuilderSettingsTest {
 
         {
             Properties props = new Properties();
-            props.setProperty(Configurable.OBJECT_WRAPPER_KEY, "Beans");
+            props.setProperty(Configurable.OBJECT_WRAPPER_KEY, "Default");
             props.setProperty(Configurable.ARITHMETIC_ENGINE_KEY, "bigdecimal");
             props.setProperty(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY, "rethrow");
             cfg.setSettings(props);
-            assertEquals(BeansWrapper.class, cfg.getObjectWrapper().getClass());
+            assertEquals(DefaultObjectWrapper.class, cfg.getObjectWrapper().getClass());
             assertSame(BigDecimalArithmeticEngine.INSTANCE, cfg.getArithmeticEngine());
             assertSame(TemplateExceptionHandler.RETHROW_HANDLER, cfg.getTemplateExceptionHandler());
             assertTrue(((WriteProtectable) cfg.getObjectWrapper()).isWriteProtected());
             assertEquals(Configuration.VERSION_3_0_0,
-                    ((BeansWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
+                    ((DefaultObjectWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
         }
         
         {
@@ -456,7 +454,7 @@ public class ObjectBuilderSettingsTest {
             assertTrue(((WriteProtectable) cfg.getObjectWrapper()).isWriteProtected());
             assertEquals(
                     Configuration.VERSION_3_0_0,
-                    ((BeansWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
+                    ((DefaultObjectWrapper) cfg.getObjectWrapper()).getIncompatibleImprovements());
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java b/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
new file mode 100644
index 0000000..b555e59
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.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 DefaultObjectWrapper ow = new DefaultObjectWrapper(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 DefaultObjectWrapper getObjectWrapper() {
+        return ow;
+    }
+    
+    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) {
+                        ow.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/AlphabeticalMethodSorter.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java b/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
new file mode 100644
index 0000000..572bd39
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.model.impl;
+
+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/CommonSupertypeForUnwrappingHintTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java b/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
new file mode 100644
index 0000000..89c488a
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.util.List;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+
+import junit.framework.TestCase;
+
+public class CommonSupertypeForUnwrappingHintTest extends TestCase {
+    
+    final OverloadedMethodsSubset oms = new DummyOverloadedMethodsSubset();
+
+    public CommonSupertypeForUnwrappingHintTest(String name) {
+        super(name);
+    }
+
+    public void testInterfaces() {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(String.class, Number.class));
+        assertEquals(C1I1.class, oms.getCommonSupertypeForUnwrappingHint(C2ExtC1I1.class, C3ExtC1I1.class));
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C4I1I2.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C5I1.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I1.class));
+        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I2.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I1.class));
+        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I2.class));
+        assertEquals(CharSequence.class, oms.getCommonSupertypeForUnwrappingHint(String.class, StringBuilder.class));
+        assertEquals(C6.class, oms.getCommonSupertypeForUnwrappingHint(C7ExtC6I1.class, C8ExtC6I1.class));
+    }
+
+    public void testArrayAndOther() {
+        testArrayAndOther(oms);
+    }
+    
+    /** These will be the same with oms and buggy: */
+    private void testArrayAndOther(OverloadedMethodsSubset oms) {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, String.class));
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, String.class));
+        
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, List.class));
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, List.class));
+        
+        assertEquals(int[].class, oms.getCommonSupertypeForUnwrappingHint(int[].class, int[].class));
+        assertEquals(Object[].class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, Object[].class));
+    }
+    
+    public void testArrayAndDifferentArray() {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, Object[].class));
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, long[].class));
+    }
+    
+    public void testPrimitive() {
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Integer.class));
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, int.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Long.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, int.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, long.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(long.class, Integer.class));
+        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(boolean.class, Boolean.class));
+        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(Boolean.class, boolean.class));
+        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(char.class, Character.class));
+        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(Character.class, char.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, short.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(short.class, int.class));
+    }
+
+    public void testMisc() {
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, Integer.class));
+        assertEquals(char.class, oms.getCommonSupertypeForUnwrappingHint(char.class, char.class));
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, Integer.class));
+        assertEquals(String.class, oms.getCommonSupertypeForUnwrappingHint(String.class, String.class));
+    }
+    
+    static interface I1 { };
+    static class C1I1 implements I1 { };
+    static class C2ExtC1I1 extends C1I1 { };
+    static class C3ExtC1I1 extends C1I1 { };
+    static interface I2 { };
+    static class C3I1I2 implements I1, I2 { };
+    static class C4I1I2 implements I1, I2 { };
+    static class C5I1 implements I1 { };
+    static interface I1I2 extends I1, I2 { };
+    static class C6 { };
+    static class C7ExtC6I1 extends C6 implements I1 { };
+    static class C8ExtC6I1 extends C6 implements I1 { };
+    
+    private static class DummyOverloadedMethodsSubset extends OverloadedMethodsSubset {
+
+        DummyOverloadedMethodsSubset() {
+            super();
+        }
+
+        @Override
+        Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
+            return memberDesc.getParamTypes();
+        }
+
+        @Override
+        void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes) {
+            // Do nothing
+        }
+
+        @Override
+        MaybeEmptyMemberAndArguments getMemberAndArguments(List tmArgs, DefaultObjectWrapper w) throws TemplateModelException {
+            throw new RuntimeException("Not implemented in this dummy.");
+        }
+        
+    }
+
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/051a0822/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java b/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
new file mode 100644
index 0000000..62e3e5f
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 java.lang.ref.Reference;
+
+import org.apache.freemarker.core.Configuration;
+import org.junit.Test;
+
+public class DefaultObjectWrapperModelFactoryRegistrationTest {
+
+    @Test
+    public void introspectionSettingChanges() {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper(Configuration.VERSION_3_0_0);
+        ClassIntrospector ci1 = ow.getClassIntrospector();
+        checkRegisteredModelFactories(ci1, ow.getStaticModels(), ow.getEnumModels(), ow.getModelCache());
+
+        ow.setExposeFields(true);
+        ClassIntrospector ci2 = ow.getClassIntrospector();
+        assertNotSame(ci1, ci2);
+        checkRegisteredModelFactories(ci1);
+        checkRegisteredModelFactories(ci2, ow.getStaticModels(), ow.getEnumModels(), ow.getModelCache());
+
+        ow.setExposureLevel(DefaultObjectWrapper.EXPOSE_ALL);
+        ClassIntrospector ci3 = ow.getClassIntrospector();
+        assertNotSame(ci2, ci3);
+        checkRegisteredModelFactories(ci2);
+        checkRegisteredModelFactories(ci3, ow.getStaticModels(), ow.getEnumModels(), ow.getModelCache());
+
+        MethodAppearanceFineTuner maf = new MethodAppearanceFineTuner() {
+            @Override
+            public void process(DecisionInput in, Decision out) {
+                // nop
+            }
+        };
+        ow.setMethodAppearanceFineTuner(maf);
+        ClassIntrospector ci4 = ow.getClassIntrospector();
+        assertNotSame(ci3, ci4);
+        checkRegisteredModelFactories(ci3);
+        checkRegisteredModelFactories(ci4, ow.getStaticModels(), ow.getEnumModels(), ow.getModelCache());
+
+        ow.setExposeFields(true);
+        assertSame(ci4, ow.getClassIntrospector());
+        ow.setExposureLevel(DefaultObjectWrapper.EXPOSE_ALL);
+        assertSame(ci4, ow.getClassIntrospector());
+        ow.setMethodAppearanceFineTuner(maf);
+        assertSame(ci4, ow.getClassIntrospector());
+        checkRegisteredModelFactories(ci4, ow.getStaticModels(), ow.getEnumModels(), ow.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("Actual 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/DefaultObjectWrapperReadOnlyTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperReadOnlyTest.java b/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperReadOnlyTest.java
new file mode 100644
index 0000000..ab18f5d
--- /dev/null
+++ b/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperReadOnlyTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.util.WriteProtectable;
+import org.apache.freemarker.core.util._ClassUtil;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests if all JavaBean properties of {@link DefaultObjectWrapper} are locked by
+ * {@link WriteProtectable#writeProtect()}.
+ */
+public class DefaultObjectWrapperReadOnlyTest extends TestCase {
+
+    private static final String EXPECTED_MESSAGE_PART = "write protected";
+
+    public DefaultObjectWrapperReadOnlyTest(String name) {
+        super(name);
+    }
+    
+    public void testDefaultObjectWrapper() throws Exception {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper(Configuration.VERSION_3_0_0);
+        ow.writeProtect();
+        checkAllPropertiesReadOnly(ow);
+    }
+    
+    private void checkAllPropertiesReadOnly(Object o) throws Exception {
+        BeanInfo bi = Introspector.getBeanInfo(o.getClass());
+        for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
+            Method setter = pd.getWriteMethod();
+            if (setter != null) {
+                Class t = pd.getPropertyType();
+                
+                Object val;
+                if (_ClassUtil.isNumerical(t)) {
+                    val = Byte.valueOf((byte) 1);
+                } else if (t == boolean.class) {
+                    val = Boolean.TRUE;
+                } else if (t == char.class) {
+                    val = Character.valueOf('c');
+                } else if (t.isAssignableFrom(String.class)) {
+                    val = "s";
+                } else {
+                    val = null;
+                }
+                try {
+                    setter.invoke(o, val);
+                    fail("This setter should have failed as the property should be read-only now: " + setter);
+                } catch (InvocationTargetException e) {
+                    Throwable target = e.getTargetException();
+                    if (!(target instanceof IllegalStateException
+                            && target.getMessage() != null
+                            && target.getMessage().contains(EXPECTED_MESSAGE_PART))) {
+                        fail("Expected IllegalStateException with message containing \"" + EXPECTED_MESSAGE_PART
+                                + "\", got this instead: " + target);
+                    }
+                }
+            }
+        }
+    }
+
+}


Mime
View raw message