You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/03/15 12:31:43 UTC

[01/10] incubator-freemarker git commit: In Eclipse excluded classes that require Java 8 language level, because setting that language level on the project will generate diamonds, which then won't compile with Java 5.

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3 0254eca3f -> 8bfb9503c


In Eclipse excluded classes that require Java 8 language level, because setting that language level on the project will generate diamonds, which then won't compile with Java 5.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/25d4695e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/25d4695e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/25d4695e

Branch: refs/heads/2.3
Commit: 25d4695e842f765fc45dac4cc2c1f756b0242d70
Parents: edc0e41
Author: ddekany <dd...@apache.org>
Authored: Tue Mar 14 14:22:14 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Mar 14 14:22:14 2017 +0100

----------------------------------------------------------------------
 README                                          |   3 +
 .../template/DefaultEnumerationAdapter.java     |   5 -
 .../beans/BeansWrapperBridgeMethodsTest.java    |  65 -----
 .../ext/beans/BeansWrapperJava8Test.java        | 239 -------------------
 .../BridgeMethodsWithDefaultMethodBean.java     |  29 ---
 .../BridgeMethodsWithDefaultMethodBean2.java    |  23 --
 .../BridgeMethodsWithDefaultMethodBeanBase.java |  31 ---
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |  28 ---
 .../Java8BeansWrapperBridgeMethodsTest.java     |  65 +++++
 .../ext/beans/Java8BeansWrapperTest.java        | 239 +++++++++++++++++++
 ...Java8BridgeMethodsWithDefaultMethodBean.java |  29 +++
 ...ava8BridgeMethodsWithDefaultMethodBean2.java |  23 ++
 ...8BridgeMethodsWithDefaultMethodBeanBase.java |  31 +++
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |  28 +++
 14 files changed, 418 insertions(+), 420 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/README
----------------------------------------------------------------------
diff --git a/README b/README
index bcd8f20..f26c29e 100644
--- a/README
+++ b/README
@@ -200,6 +200,8 @@ apply it to your development environment:
    - Press "Finish"
 - Eclipse will indicate many errors at this point; it's expected, read on.
 - Project -> Properties -> Java Compiler
+  - Set "Compiler Compliance Level" to "1.5" (you will have to uncheck
+    "Use compliance from execution environment" for that)
   - In Errors/Warnings, check in "Enable project specific settings", then set
     "Forbidden reference (access rules)" from "Error" to "Warning".
 - You will still have errors on these java files (because different java
@@ -210,6 +212,7 @@ apply it to your development environment:
     _Jython22*.java
     _FreeMarkerPageContext2.java
     FreeMarkerJspFactory2.java
+    Java8*.java
   Also, close these files if they are open. Now you shouldn't have any errors.
 - At Project -> Properties -> Java Code Style -> Formatter, check in "Enable
   project specific settings", and then select "FreeMarker" as active profile.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/main/java/freemarker/template/DefaultEnumerationAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/DefaultEnumerationAdapter.java b/src/main/java/freemarker/template/DefaultEnumerationAdapter.java
index 59549b4..6a26fc1 100644
--- a/src/main/java/freemarker/template/DefaultEnumerationAdapter.java
+++ b/src/main/java/freemarker/template/DefaultEnumerationAdapter.java
@@ -56,17 +56,14 @@ public class DefaultEnumerationAdapter extends WrappingTemplateModel implements
         this.enumeration = enumeration;
     }
 
-    @Override
     public Object getWrappedObject() {
         return enumeration;
     }
 
-    @Override
     public Object getAdaptedObject(Class<?> hint) {
         return getWrappedObject();
     }
 
-    @Override
     public TemplateModelIterator iterator() throws TemplateModelException {
         return new SimpleTemplateModelIterator();
     }
@@ -82,7 +79,6 @@ public class DefaultEnumerationAdapter extends WrappingTemplateModel implements
 
         private boolean enumerationOwnedByMe;
 
-        @Override
         public TemplateModel next() throws TemplateModelException {
             if (!enumerationOwnedByMe) {
                 checkNotOwner();
@@ -98,7 +94,6 @@ public class DefaultEnumerationAdapter extends WrappingTemplateModel implements
             return value instanceof TemplateModel ? (TemplateModel) value : wrap(value);
         }
 
-        @Override
         public boolean hasNext() throws TemplateModelException {
             // Calling hasNext may looks safe, but I have met sync. problems.
             if (!enumerationOwnedByMe) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java b/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
deleted file mode 100644
index 634fae4..0000000
--- a/src/test/java/freemarker/ext/beans/BeansWrapperBridgeMethodsTest.java
+++ /dev/null
@@ -1,65 +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 freemarker.ext.beans;
-
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-
-import org.junit.Test;
-
-import freemarker.template.Configuration;
-import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateMethodModelEx;
-import freemarker.template.TemplateModelException;
-
-public class BeansWrapperBridgeMethodsTest {
-    
-    @Test
-    public void testWithoutDefaultMethod() throws TemplateModelException {
-        test(BridgeMethodsBean.class);
-    }
-
-    @Test
-    public void testWithDefaultMethod() throws TemplateModelException {
-        test(BridgeMethodsWithDefaultMethodBean.class);
-    }
-
-    @Test
-    public void testWithDefaultMethod2() throws TemplateModelException {
-        test(BridgeMethodsWithDefaultMethodBean2.class);
-    }
-
-    private void test(Class<?> pClass) throws TemplateModelException {
-        BeansWrapper ow = new BeansWrapperBuilder(Configuration.VERSION_2_3_26).build();
-        TemplateHashModel wrapped;
-        try {
-            wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance());
-        } catch (Exception e) {
-            throw new IllegalStateException(e);
-        }
-        
-        TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1");
-        assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList()));
-        
-        TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2");
-        assertNull(m2.exec(Collections.emptyList()));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BeansWrapperJava8Test.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BeansWrapperJava8Test.java b/src/test/java/freemarker/ext/beans/BeansWrapperJava8Test.java
deleted file mode 100644
index abdb0f5..0000000
--- a/src/test/java/freemarker/ext/beans/BeansWrapperJava8Test.java
+++ /dev/null
@@ -1,239 +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 freemarker.ext.beans;
-
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-
-import org.junit.Test;
-
-import freemarker.template.Configuration;
-import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateMethodModelEx;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateNumberModel;
-import freemarker.template.TemplateScalarModel;
-import freemarker.template.TemplateSequenceModel;
-
-public class BeansWrapperJava8Test {
-
-    @Test
-    public void testDefaultMethodNotRecognized() throws TemplateModelException {
-        BeansWrapperBuilder owb = new BeansWrapperBuilder(Configuration.VERSION_2_3_0);
-        // owb.setTreatDefaultMethodsAsBeanMembers(false);
-        BeansWrapper ow = owb.build();
-        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
-        
-        {
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
-        }
-        {
-            // This is overridden in the subclass, so it's visible even without default method support: 
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
-        }
-        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP));
-        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP));
-        {
-            // We don't see the default method indexed reader, but see the plain reader method in the subclass.
-            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
-        }
-        {
-            // We don't see the default method non-indexed reader that would spoil the indexed reader in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_2_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We don't see the default method non-indexed reader that would spoil the indexed reader in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_3_VALUE,
-                    ((TemplateNumberModel) prop.get(0)).getAsNumber());
-        }
-        {
-            // We don't see the default method indexed reader, but see the plain array reader in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // Only present in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.INDEXED_PROP_4);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }        
-        {
-            // We don't see the default method non-indexed reader
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_3_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.NORMAL_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_ACTION));
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-    }
-    
-    @Test
-    public void testDefaultMethodRecognized() throws TemplateModelException {
-        BeansWrapperBuilder owb = new BeansWrapperBuilder(Configuration.VERSION_2_3_0);
-        owb.setTreatDefaultMethodsAsBeanMembers(true);
-        BeansWrapper ow = owb.build();
-        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
-        
-        {
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
-        }
-        {
-            // This is overridden in the subclass, so it's visible even without default method support: 
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
-        }
-        {
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString());
-        }
-        {
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We see default method indexed read method, but it's invalidated by normal getter in the subclass
-            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
-        }
-        {
-            // The default method read method invalidates the indexed read method in the subclass
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString());
-        }
-        {
-            // The default method read method invalidates the indexed read method in the subclass
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We see the default method indexed reader, which overrides the plain array reader in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that
-            // takes over.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_3_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }        
-        {
-            // Only present in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.INDEXED_PROP_4);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }        
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.NORMAL_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.NORMAL_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
deleted file mode 100644
index 25b67fe..0000000
--- a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean.java
+++ /dev/null
@@ -1,29 +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 freemarker.ext.beans;
-
-public class BridgeMethodsWithDefaultMethodBean implements BridgeMethodsWithDefaultMethodBeanBase<String> {
-
-    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
-    
-    public String m1() {
-        return M1_RETURN_VALUE;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
deleted file mode 100644
index a2261c9..0000000
--- a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBean2.java
+++ /dev/null
@@ -1,23 +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 freemarker.ext.beans;
-
-public class BridgeMethodsWithDefaultMethodBean2 implements BridgeMethodsWithDefaultMethodBeanBase2 {
-    // All inherited
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
deleted file mode 100644
index 2dbd459..0000000
--- a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase.java
+++ /dev/null
@@ -1,31 +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 freemarker.ext.beans;
-
-public interface BridgeMethodsWithDefaultMethodBeanBase<T> {
-
-    default T m1() {
-        return null;
-    }
-    
-    default T m2() {
-        return null;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java b/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
deleted file mode 100644
index 2886d8f..0000000
--- a/src/test/java/freemarker/ext/beans/BridgeMethodsWithDefaultMethodBeanBase2.java
+++ /dev/null
@@ -1,28 +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 freemarker.ext.beans;
-
-public interface BridgeMethodsWithDefaultMethodBeanBase2 extends BridgeMethodsWithDefaultMethodBeanBase<String> {
-
-    @Override
-    default String m1() {
-        return BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BeansWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BeansWrapperBridgeMethodsTest.java b/src/test/java/freemarker/ext/beans/Java8BeansWrapperBridgeMethodsTest.java
new file mode 100644
index 0000000..11d1d9e
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BeansWrapperBridgeMethodsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
+
+public class Java8BeansWrapperBridgeMethodsTest {
+    
+    @Test
+    public void testWithoutDefaultMethod() throws TemplateModelException {
+        test(BridgeMethodsBean.class);
+    }
+
+    @Test
+    public void testWithDefaultMethod() throws TemplateModelException {
+        test(Java8BridgeMethodsWithDefaultMethodBean.class);
+    }
+
+    @Test
+    public void testWithDefaultMethod2() throws TemplateModelException {
+        test(Java8BridgeMethodsWithDefaultMethodBean2.class);
+    }
+
+    private void test(Class<?> pClass) throws TemplateModelException {
+        BeansWrapper ow = new BeansWrapperBuilder(Configuration.VERSION_2_3_26).build();
+        TemplateHashModel wrapped;
+        try {
+            wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance());
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        
+        TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1");
+        assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList()));
+        
+        TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2");
+        assertNull(m2.exec(Collections.emptyList()));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BeansWrapperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BeansWrapperTest.java b/src/test/java/freemarker/ext/beans/Java8BeansWrapperTest.java
new file mode 100644
index 0000000..e385dab
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BeansWrapperTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+import freemarker.template.TemplateScalarModel;
+import freemarker.template.TemplateSequenceModel;
+
+public class Java8BeansWrapperTest {
+
+    @Test
+    public void testDefaultMethodNotRecognized() throws TemplateModelException {
+        BeansWrapperBuilder owb = new BeansWrapperBuilder(Configuration.VERSION_2_3_0);
+        // owb.setTreatDefaultMethodsAsBeanMembers(false);
+        BeansWrapper ow = owb.build();
+        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
+        
+        {
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
+        }
+        {
+            // This is overridden in the subclass, so it's visible even without default method support: 
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
+        }
+        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP));
+        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP));
+        {
+            // We don't see the default method indexed reader, but see the plain reader method in the subclass.
+            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
+        }
+        {
+            // We don't see the default method non-indexed reader that would spoil the indexed reader in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_2_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We don't see the default method non-indexed reader that would spoil the indexed reader in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_3_VALUE,
+                    ((TemplateNumberModel) prop.get(0)).getAsNumber());
+        }
+        {
+            // We don't see the default method indexed reader, but see the plain array reader in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // Only present in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.INDEXED_PROP_4);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }        
+        {
+            // We don't see the default method non-indexed reader
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_3_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.NORMAL_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_ACTION));
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+    }
+    
+    @Test
+    public void testDefaultMethodRecognized() throws TemplateModelException {
+        BeansWrapperBuilder owb = new BeansWrapperBuilder(Configuration.VERSION_2_3_0);
+        owb.setTreatDefaultMethodsAsBeanMembers(true);
+        BeansWrapper ow = owb.build();
+        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
+        
+        {
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
+        }
+        {
+            // This is overridden in the subclass, so it's visible even without default method support: 
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
+        }
+        {
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString());
+        }
+        {
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We see default method indexed read method, but it's invalidated by normal getter in the subclass
+            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
+        }
+        {
+            // The default method read method invalidates the indexed read method in the subclass
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString());
+        }
+        {
+            // The default method read method invalidates the indexed read method in the subclass
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We see the default method indexed reader, which overrides the plain array reader in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that
+            // takes over.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_3_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }        
+        {
+            // Only present in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.INDEXED_PROP_4);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }        
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.NORMAL_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.NORMAL_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean.java b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean.java
new file mode 100644
index 0000000..d6df29f
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+public class Java8BridgeMethodsWithDefaultMethodBean implements Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
+    
+    public String m1() {
+        return M1_RETURN_VALUE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean2.java b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean2.java
new file mode 100644
index 0000000..b61c2af
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBean2.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+public class Java8BridgeMethodsWithDefaultMethodBean2 implements Java8BridgeMethodsWithDefaultMethodBeanBase2 {
+    // All inherited
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase.java b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase.java
new file mode 100644
index 0000000..7ef0b1c
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+public interface Java8BridgeMethodsWithDefaultMethodBeanBase<T> {
+
+    default T m1() {
+        return null;
+    }
+    
+    default T m2() {
+        return null;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/25d4695e/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase2.java b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
new file mode 100644
index 0000000..aa218f5
--- /dev/null
+++ b/src/test/java/freemarker/ext/beans/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.ext.beans;
+
+public interface Java8BridgeMethodsWithDefaultMethodBeanBase2 extends Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+    @Override
+    default String m1() {
+        return Java8BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE;
+    }
+    
+}


[02/10] incubator-freemarker git commit: Environment independence of tests: DecimalFormat symbols

Posted by dd...@apache.org.
Environment independence of tests: DecimalFormat symbols


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/738cef85
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/738cef85
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/738cef85

Branch: refs/heads/2.3
Commit: 738cef854c5341fe75243881fd454577151064d2
Parents: 25d4695
Author: ddekany <dd...@apache.org>
Authored: Tue Mar 14 15:26:17 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Mar 14 15:26:17 2017 +0100

----------------------------------------------------------------------
 .../core/ExtendedDecimalFormatTest.java         | 27 +++++++++++---------
 1 file changed, 15 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/738cef85/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java b/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
index da77096..17a699e 100644
--- a/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
+++ b/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.*;
 
 import java.io.IOException;
 import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
 import java.text.ParseException;
 import java.util.Locale;
 
@@ -36,12 +37,13 @@ import freemarker.test.TemplateTest;
 public class ExtendedDecimalFormatTest extends TemplateTest {
     
     private static final Locale LOC = Locale.US;
+    private static final DecimalFormatSymbols SYMS = DecimalFormatSymbols.getInstance(LOC);
     
     @Test
     public void testNonExtended() throws ParseException {
         for (String fStr : new String[] { "0.00", "0.###", "#,#0.###", "#0.####", "0.0;m", "0.0;",
                 "0'x'", "0'x';'m'", "0';'", "0';';m", "0';';'#'m';'", "0';;'", "" }) {
-            assertFormatsEquivalent(new DecimalFormat(fStr), ExtendedDecimalFormatParser.parse(fStr, LOC));
+            assertFormatsEquivalent(new DecimalFormat(fStr, SYMS), ExtendedDecimalFormatParser.parse(fStr, LOC));
         }
         
         try {
@@ -59,17 +61,18 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
 
     @Test
     public void testNonExtended2() throws ParseException {
-        assertFormatsEquivalent(new DecimalFormat("0.0"), ExtendedDecimalFormatParser.parse("0.0;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0.0"), ExtendedDecimalFormatParser.parse("0.0;;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0.0;m"), ExtendedDecimalFormatParser.parse("0.0;m;", LOC));
-        assertFormatsEquivalent(new DecimalFormat(""), ExtendedDecimalFormatParser.parse(";;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0'x'"), ExtendedDecimalFormatParser.parse("0'x';;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0'x';'m'"), ExtendedDecimalFormatParser.parse("0'x';'m';", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';'"), ExtendedDecimalFormatParser.parse("0';';;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';';m"), ExtendedDecimalFormatParser.parse("0';';m;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';';'#'m';'"), ExtendedDecimalFormatParser.parse("0';';'#'m';';",
-                LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';;'"), ExtendedDecimalFormatParser.parse("0';;';;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0.0;m", SYMS), ExtendedDecimalFormatParser.parse("0.0;m;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("", SYMS), ExtendedDecimalFormatParser.parse(";;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0'x'", SYMS), ExtendedDecimalFormatParser.parse("0'x';;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0'x';'m'", SYMS),
+                ExtendedDecimalFormatParser.parse("0'x';'m';", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';'", SYMS), ExtendedDecimalFormatParser.parse("0';';;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';';m", SYMS), ExtendedDecimalFormatParser.parse("0';';m;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';';'#'m';'", SYMS),
+                ExtendedDecimalFormatParser.parse("0';';'#'m';';", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';;'", SYMS), ExtendedDecimalFormatParser.parse("0';;';;", LOC));
         
         try {
             new DecimalFormat(";m");


[10/10] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/8bfb9503
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/8bfb9503
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/8bfb9503

Branch: refs/heads/2.3
Commit: 8bfb9503c69b943a451fa54dd0f0431810e5901c
Parents: e98aa75 36305d0
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 13:31:29 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 13:31:29 2017 +0100

----------------------------------------------------------------------
 build.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8bfb9503/build.xml
----------------------------------------------------------------------


[06/10] incubator-freemarker git commit: (?sort_by error message adjustment)

Posted by dd...@apache.org.
(?sort_by error message adjustment)


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/51984865
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/51984865
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/51984865

Branch: refs/heads/2.3
Commit: 519848652bd1dfceaedbbadf37463a5756ed710a
Parents: 5f41821
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 11:38:38 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 11:38:38 2017 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/core/BuiltInsForSequences.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51984865/src/main/java/freemarker/core/BuiltInsForSequences.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForSequences.java b/src/main/java/freemarker/core/BuiltInsForSequences.java
index 4139534..609f53e 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -698,7 +698,7 @@ class BuiltInsForSequences {
                     if (key == null) {
                         throw new _TemplateModelException(
                                 startErrorMessage(keyNamesLn, i),
-                                "The " + StringUtil.jQuote(keyNames[keyNameI]), " subvariable was not found.");
+                                "The " + StringUtil.jQuote(keyNames[keyNameI]), " subvariable was null or missing.");
                     }
                 } // for each key
                 


[05/10] incubator-freemarker git commit: Manual: Clarified that container in FTL are immutable.

Posted by dd...@apache.org.
Manual: Clarified that container in FTL are immutable.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/5f418218
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/5f418218
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/5f418218

Branch: refs/heads/2.3
Commit: 5f418218b7669573baeca8e53cb08f1b5fd6d57a
Parents: 649d85d
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 11:38:13 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 11:38:13 2017 +0100

----------------------------------------------------------------------
 src/manual/en_US/book.xml | 41 +++++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5f418218/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 5673870..beab00d 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -1406,6 +1406,15 @@ brown</programlisting>
 
           <para>The data-model itself (or better said the root of it) is a
           hash.</para>
+
+          <para>FreeMarker templates don't support modifying the contents of
+          containers (such as adding, removing or replacing sub variables),
+          and it assumes that their content won't change during template
+          processing. (But you can make new container values by adding
+          together two existing container values with <literal>+</literal>;
+          see that in the <link linkend="exp_cheatsheet">chapter about
+          expressions</link>, and please note the performance
+          consequences.)</para>
         </section>
 
         <section>
@@ -3079,11 +3088,12 @@ CDEF</programlisting>
             repeated concatenations, like for appending items to a sequence
             inside a loop. It's just for things like <literal>&lt;#list users
             + admins as person&gt;</literal>. Although concatenating sequences
-            is fast and its speed is independently of the size of the
-            concatenated sequences, the resulting sequence will be always a
-            little bit slower to read than the original two sequences were.
-            This way the result of many repeated concatenations is a sequence
-            that is slow to read.</para>
+            is fast and is constant time (it's speed is independently of the
+            size of the concatenated sequences), the resulting sequence will
+            be always a little bit slower to read than the original two
+            sequences were. Thus, after tens or hundreds of repeated
+            concatenations the result can be impractically slow to
+            reader.</para>
           </section>
 
           <section xml:id="dgui_template_exp_seqenceop_slice">
@@ -3232,9 +3242,11 @@ Slicing with right-unlimited ranges:
 
             <para>Note that hash concatenation is not to be used for many
             repeated concatenations, like for adding items to a hash inside a
-            loop. It's the same as with the <link
-            linkend="dgui_template_exp_sequenceop_cat">sequence
-            concatenation</link>.</para>
+            loop. While adding together hashes is fast and is constant time
+            (independent of the size of the hashes added), the resulting hash
+            is a bit slower to read than the hashes added together. Thus after
+            tens or hundreds of additions the result can be impractically slow
+            to read.</para>
           </section>
         </section>
 
@@ -18622,8 +18634,17 @@ or
               string literal does not expand interpolations (as
               <literal>"${foo}"</literal>); if you need to assign to a
               dynamically constructed name, the you have to use <link
-              linkend="faq_assign_to_dynamic_variable_name">this
-              trick</link>.</para>
+              linkend="faq_assign_to_dynamic_variable_name">a different
+              trick</link>. Note that because the FreeMarker template language
+              assumes that sequences (lists, arrays, etc.) and hashes (maps,
+              beans, etc.) are immutable, you can <emphasis>not</emphasis>
+              write something like <literal>&lt;#assign myObj.someProperty =
+              'will NOT work'&gt;</literal> or <literal>&lt;#assign myList[0]
+              = 'will NOT work'&gt;</literal>. However, adding sequences or
+              hashes with the <literal>+</literal> operator to form another
+              value is supported; see in the <link
+              linkend="exp_cheatsheet">chapter about expressions</link>, and
+              please note the performance consequences.</para>
             </listitem>
 
             <listitem>


[03/10] incubator-freemarker git commit: Added Configuration.isXxxExplictlySet and Configuration.unsetXxx methods for the Configuration settings: locale, time_zone, default_encoding. (This can be utilized in frameworks to detect if the application has mi

Posted by dd...@apache.org.
Added Configuration.isXxxExplictlySet and Configuration.unsetXxx methods for the Configuration settings: locale, time_zone, default_encoding. (This can be utilized in frameworks to detect if the application has missed setting these. The backward compatible default values are often unwanted, as they are the default locale, time zone and file encoding of the Java environment.)

The locale and default_encoding configuration settings now supports the special "JVM default" value when set from Java .properties file, or via Configuration.setSettings(Properties), or via the #setting directive. Earlier only the time_zone setting has supported this value.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/0fa42996
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/0fa42996
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/0fa42996

Branch: refs/heads/2.3
Commit: 0fa4299657306fba0e18d732b122e1ca09d7b54e
Parents: 738cef8
Author: ddekany <dd...@apache.org>
Authored: Tue Mar 14 20:13:25 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Mar 14 20:13:25 2017 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/core/Configurable.java |  16 ++-
 .../java/freemarker/template/Configuration.java | 109 ++++++++++++++++++-
 .../java/freemarker/template/_TemplateAPI.java  |  10 ++
 src/manual/en_US/book.xml                       |  29 ++++-
 .../freemarker/template/ConfigurationTest.java  |  63 +++++++++++
 5 files changed, 218 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0fa42996/src/main/java/freemarker/core/Configurable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index 76a3922..1563a4e 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -388,10 +388,10 @@ public class Configurable {
         parent = null;
         properties = new Properties();
         
-        locale = Locale.getDefault();
+        locale = _TemplateAPI.getDefaultLocale();
         properties.setProperty(LOCALE_KEY, locale.toString());
         
-        timeZone = TimeZone.getDefault();
+        timeZone = _TemplateAPI.getDefaultTimeZone();
         properties.setProperty(TIME_ZONE_KEY, timeZone.getID());
         
         sqlDataAndTimeTimeZone = null;
@@ -1992,7 +1992,8 @@ public class Configurable {
      * <ul>
      *   <li><p>{@code "locale"}:
      *       See {@link #setLocale(Locale)}.
-     *       <br>String value: local codes with the usual format in Java, such as {@code "en_US"}.
+     *       <br>String value: local codes with the usual format in Java, such as {@code "en_US"}, or since 2.3.26,
+     *       "JVM default" (ignoring case) to use the default locale of the Java environment.
      *       
      *   <li><p>{@code "classic_compatible"}:
      *       See {@link #setClassicCompatible(boolean)} and {@link Configurable#setClassicCompatibleAsInt(int)}.
@@ -2179,7 +2180,8 @@ public class Configurable {
      *       {@code "disable"} for {@link Configuration#DISABLE_AUTO_ESCAPING_POLICY}.
      *       
      *   <li><p>{@code "default_encoding"}:
-     *       See {@link Configuration#setDefaultEncoding(String)}.
+     *       See {@link Configuration#setDefaultEncoding(String)}; since 2.3.26 also accepts value "JVM default"
+     *       (not case sensitive) to set the Java environment default value.
      *       <br>As the default value is the system default, which can change
      *       from one server to another, <b>you should always set this!</b>
      *       
@@ -2385,7 +2387,11 @@ public class Configurable {
         boolean unknown = false;
         try {
             if (LOCALE_KEY.equals(name)) {
-                setLocale(StringUtil.deduceLocale(value));
+                if (JVM_DEFAULT.equalsIgnoreCase(value)) {
+                    setLocale(Locale.getDefault());
+                } else {
+                    setLocale(StringUtil.deduceLocale(value));
+                }
             } else if (NUMBER_FORMAT_KEY_SNAKE_CASE.equals(name) || NUMBER_FORMAT_KEY_CAMEL_CASE.equals(name)) {
                 setNumberFormat(value);
             } else if (CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE.equals(name)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0fa42996/src/main/java/freemarker/template/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index a34c605..ca5ee72 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -38,6 +38,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
+import java.util.TimeZone;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -424,6 +425,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     
     private static final String NULL = "null";
     private static final String DEFAULT = "default";
+    private static final String JVM_DEFAULT = "JVM default";
     
     private static final Version VERSION;
     static {
@@ -509,6 +511,10 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     private boolean objectWrapperExplicitlySet;
     private boolean templateExceptionHandlerExplicitlySet;
     private boolean logTemplateExceptionsExplicitlySet;
+    private boolean localeExplicitlySet;
+    private boolean defaultEncodingExplicitlySet;
+    private boolean timeZoneExplicitlySet;
+
     
     private HashMap/*<String, TemplateModel>*/ sharedVariables = new HashMap();
 
@@ -519,7 +525,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
      */
     private HashMap/*<String, Object>*/ rewrappableSharedVariables = null;
     
-    private String defaultEncoding = SecurityUtilities.getSystemProperty("file.encoding", "utf-8");
+    private String defaultEncoding = getDefaultDefaultEncoding();
     private ConcurrentMap localeToCharsetMap = new ConcurrentHashMap();
     
     /**
@@ -1606,6 +1612,70 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     }
     
     @Override
+    public void setLocale(Locale locale) {
+        super.setLocale(locale);
+        localeExplicitlySet = true;
+    }
+    
+    /**
+     * Resets the setting to its default, as if it was never set.
+     * 
+     * @since 2.3.26
+     */
+    public void unsetLocale() {
+        if (localeExplicitlySet) {
+            setLocale(getDefaultLocale());
+            localeExplicitlySet = false;
+        }
+    }
+    
+    /**
+     * Tells if {@link #setLocale(Locale)} (or equivalent) was already called on this instance, or it just holds the
+     * default value.
+     * 
+     * @since 2.3.26
+     */
+    public boolean isLocaleExplicitlySet() {
+        return localeExplicitlySet;
+    }
+    
+    static Locale getDefaultLocale() {
+        return Locale.getDefault();
+    }
+    
+    @Override
+    public void setTimeZone(TimeZone timeZone) {
+        super.setTimeZone(timeZone);
+        timeZoneExplicitlySet = true;
+    }
+    
+    /**
+     * Resets the setting to its default, as if it was never set.
+     * 
+     * @since 2.3.26
+     */
+    public void unsetTimeZone() {
+        if (timeZoneExplicitlySet) {
+            setTimeZone(getDefaultTimeZone());
+            timeZoneExplicitlySet = false;
+        }
+    }
+    
+    /**
+     * Tells if {@link #setTimeZone(TimeZone)} (or equivalent) was already called on this instance, or it just holds the
+     * default value.
+     * 
+     * @since 2.3.26
+     */
+    public boolean isTimeZoneExplicitlySet() {
+        return timeZoneExplicitlySet;
+    }
+    
+    static TimeZone getDefaultTimeZone() {
+        return TimeZone.getDefault();
+    }
+    
+    @Override
     public void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) {
         super.setTemplateExceptionHandler(templateExceptionHandler);
         templateExceptionHandlerExplicitlySet = true;
@@ -2534,6 +2604,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
      */
     public void setDefaultEncoding(String encoding) {
         defaultEncoding = encoding;
+        defaultEncodingExplicitlySet = true;
     }
 
     /**
@@ -2544,7 +2615,37 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     public String getDefaultEncoding() {
         return defaultEncoding;
     }
+    
+    /**
+     * Resets the setting to its default, as if it was never set.
+     * 
+     * @since 2.3.26
+     */
+    public void unsetDefaultEncoding() {
+        if (defaultEncodingExplicitlySet) {
+            setDefaultEncoding(getDefaultDefaultEncoding());
+            defaultEncodingExplicitlySet = false;
+        }
+    }
+    
+    /**
+     * Tells if {@link #setDefaultEncoding(String)} (or equivalent) was already called on this instance, or it just holds the
+     * default value.
+     * 
+     * @since 2.3.26
+     */
+    public boolean isDefaultEncodingExplicitlySet() {
+        return defaultEncodingExplicitlySet;
+    }
+    
+    static private String getDefaultDefaultEncoding() {
+        return getJVMDefaultEncoding();
+    }
 
+    static private String getJVMDefaultEncoding() {
+        return SecurityUtilities.getSystemProperty("file.encoding", "utf-8");
+    }
+    
     /**
      * Gets the preferred character encoding for the given locale, or the 
      * default encoding if no encoding is set explicitly for the specified
@@ -2845,7 +2946,11 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
             }
             
             if (DEFAULT_ENCODING_KEY_SNAKE_CASE.equals(name) || DEFAULT_ENCODING_KEY_CAMEL_CASE.equals(name)) {
-                setDefaultEncoding(value);
+                if (JVM_DEFAULT.equalsIgnoreCase(value)) {
+                    setDefaultEncoding(getJVMDefaultEncoding()); 
+                } else {
+                    setDefaultEncoding(value);
+                }
             } else if (LOCALIZED_LOOKUP_KEY_SNAKE_CASE.equals(name) || LOCALIZED_LOOKUP_KEY_CAMEL_CASE.equals(name)) {
                 setLocalizedLookup(StringUtil.getYesNo(value));
             } else if (STRICT_SYNTAX_KEY_SNAKE_CASE.equals(name) || STRICT_SYNTAX_KEY_CAMEL_CASE.equals(name)) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0fa42996/src/main/java/freemarker/template/_TemplateAPI.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/_TemplateAPI.java b/src/main/java/freemarker/template/_TemplateAPI.java
index 15d5e23..737c528 100644
--- a/src/main/java/freemarker/template/_TemplateAPI.java
+++ b/src/main/java/freemarker/template/_TemplateAPI.java
@@ -19,7 +19,9 @@
 
 package freemarker.template;
 
+import java.util.Locale;
 import java.util.Set;
+import java.util.TimeZone;
 
 import freemarker.cache.CacheStorage;
 import freemarker.cache.TemplateLoader;
@@ -150,4 +152,12 @@ public class _TemplateAPI {
         return e.getBlamedExpression();
     }
     
+    public static Locale getDefaultLocale() {
+        return Configuration.getDefaultLocale();
+    }
+    
+    public static TimeZone getDefaultTimeZone() {
+        return Configuration.getDefaultTimeZone();
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0fa42996/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 7ba4089..5673870 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -26862,8 +26862,8 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               <literal>Configuration</literal> on its default, it's enough to
               increase the <literal>incompatibleImprovements</literal> setting
               of the <literal>Configuration</literal> to 2.3.26, as that's
-              inherited by the default <literal>object_wrapper</literal>.
-              </para>
+              inherited by the default
+              <literal>object_wrapper</literal>.</para>
             </listitem>
 
             <listitem>
@@ -26895,6 +26895,31 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
+              <para>Added
+              <literal>Configuration.is<replaceable>Xxx</replaceable>ExplictlySet</literal>
+              and
+              <literal>Configuration.unset<replaceable>Xxx</replaceable></literal>
+              methods for the Configuration settings:
+              <literal>locale</literal>, <literal>time_zone</literal>,
+              <literal>default_encoding</literal>. (This can be utilized in
+              frameworks to detect if the application has missed setting
+              these. The backward compatible default values are often
+              unwanted, as they are the default locale, time zone and file
+              encoding of the Java environment.)</para>
+            </listitem>
+
+            <listitem>
+              <para>The <literal>locale</literal> and
+              <literal>default_encoding</literal> configuration settings now
+              supports the special <literal>"JVM default"</literal> value when
+              set from Java <literal>.properties</literal> file, or via
+              <literal>Configuration.setSettings(Properties)</literal>, or via
+              the <literal>#setting</literal> directive. Earlier only the
+              <literal>time_zone</literal> setting has supported this
+              value.</para>
+            </listitem>
+
+            <listitem>
               <para>Bug fixed: If <link
               linkend="pgui_config_incompatible_improvements_how_to_set">the
               <literal>incompatible_improvements</literal> setting</link> is

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0fa42996/src/test/java/freemarker/template/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index a4dbfcc..15ba915 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -1615,6 +1615,69 @@ public class ConfigurationTest extends TestCase {
         assertTrue(cfg.isLazyAutoImportsSet());
     }
     
+    public void testLocaleSetting() throws TemplateException {
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+        
+        assertEquals(Locale.getDefault(), cfg.getLocale());
+        assertFalse(cfg.isLocaleExplicitlySet());
+        
+        Locale nonDefault = Locale.getDefault().equals(Locale.GERMANY) ? Locale.FRANCE : Locale.GERMANY;
+        cfg.setLocale(nonDefault);
+        assertTrue(cfg.isLocaleExplicitlySet());
+        assertEquals(nonDefault, cfg.getLocale());
+        
+        cfg.unsetLocale();
+        assertEquals(Locale.getDefault(), cfg.getLocale());
+        assertFalse(cfg.isLocaleExplicitlySet());
+        
+        cfg.setSetting(Configuration.LOCALE_KEY, "JVM default");
+        assertEquals(Locale.getDefault(), cfg.getLocale());
+        assertTrue(cfg.isLocaleExplicitlySet());
+    }
+    
+    public void testDefaultEncodingSetting() throws TemplateException {
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+        
+        String defaultFileEncoding = System.getProperty("file.encoding");
+        assertNotNull(defaultFileEncoding);
+        
+        assertEquals(defaultFileEncoding, cfg.getDefaultEncoding());
+        assertFalse(cfg.isDefaultEncodingExplicitlySet());
+        
+        String nonDefault = defaultFileEncoding.equalsIgnoreCase("UTF-8") ? "ISO-8859-1" : "UTF-8";
+        cfg.setDefaultEncoding(nonDefault);
+        assertTrue(cfg.isDefaultEncodingExplicitlySet());
+        assertEquals(nonDefault, cfg.getDefaultEncoding());
+        
+        cfg.unsetDefaultEncoding();
+        assertEquals(defaultFileEncoding, cfg.getDefaultEncoding());
+        assertFalse(cfg.isDefaultEncodingExplicitlySet());
+        
+        cfg.setSetting(Configuration.DEFAULT_ENCODING_KEY, "JVM default");
+        assertEquals(defaultFileEncoding, cfg.getDefaultEncoding());
+        assertTrue(cfg.isDefaultEncodingExplicitlySet());
+    }
+    
+    public void testTimeZoneSetting() throws TemplateException {
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+        
+        assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+        assertFalse(cfg.isTimeZoneExplicitlySet());
+        
+        TimeZone nonDefault = TimeZone.getDefault().equals(DateUtil.UTC) ? TimeZone.getTimeZone("PST") : DateUtil.UTC;
+        cfg.setTimeZone(nonDefault);
+        assertTrue(cfg.isTimeZoneExplicitlySet());
+        assertEquals(nonDefault, cfg.getTimeZone());
+        
+        cfg.unsetTimeZone();
+        assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+        assertFalse(cfg.isTimeZoneExplicitlySet());
+        
+        cfg.setSetting(Configuration.TIME_ZONE_KEY, "JVM default");
+        assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+        assertTrue(cfg.isTimeZoneExplicitlySet());
+    }
+    
     @Test
     public void testGetSettingNamesAreSorted() throws Exception {
         Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);


[08/10] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/e98aa75d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/e98aa75d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/e98aa75d

Branch: refs/heads/2.3
Commit: e98aa75d44c391f0418eb9e28fde745947c15b96
Parents: 0254eca ca52e2d
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 13:20:12 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 13:20:12 2017 +0100

----------------------------------------------------------------------
 .gitattributes                                  |  17 ++
 .gitignore                                      |  17 ++
 README                                          |   3 +
 .../freemarker/core/BuiltInsForSequences.java   |   2 +-
 src/main/java/freemarker/core/Configurable.java |  16 +-
 .../java/freemarker/template/Configuration.java | 109 ++++++++-
 .../template/DefaultEnumerationAdapter.java     |   5 -
 .../java/freemarker/template/_TemplateAPI.java  |  10 +
 src/manual/en_US/book.xml                       |  70 +++++-
 .../core/ExtendedDecimalFormatTest.java         |  27 ++-
 .../java/freemarker/core/SQLTimeZoneTest.java   |   2 +
 .../beans/BeansWrapperBridgeMethodsTest.java    |  65 -----
 .../ext/beans/BeansWrapperJava8Test.java        | 239 -------------------
 .../BridgeMethodsWithDefaultMethodBean.java     |  29 ---
 .../BridgeMethodsWithDefaultMethodBean2.java    |  23 --
 .../BridgeMethodsWithDefaultMethodBeanBase.java |  31 ---
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |  28 ---
 .../Java8BeansWrapperBridgeMethodsTest.java     |  65 +++++
 .../ext/beans/Java8BeansWrapperTest.java        | 239 +++++++++++++++++++
 ...Java8BridgeMethodsWithDefaultMethodBean.java |  29 +++
 ...ava8BridgeMethodsWithDefaultMethodBean2.java |  23 ++
 ...8BridgeMethodsWithDefaultMethodBeanBase.java |  31 +++
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |  28 +++
 .../freemarker/template/ConfigurationTest.java  |  63 +++++
 src/test/java/freemarker/test/TemplateTest.java |  19 ++
 25 files changed, 738 insertions(+), 452 deletions(-)
----------------------------------------------------------------------



[04/10] incubator-freemarker git commit: Ensure that the configuration settings don't depend on the machine that runs the test.

Posted by dd...@apache.org.
Ensure that the configuration settings don't depend on the machine that runs the test.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/649d85d1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/649d85d1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/649d85d1

Branch: refs/heads/2.3
Commit: 649d85d180cdd3df87a79e2357d9d77a384dcccf
Parents: 0fa4299
Author: ddekany <dd...@apache.org>
Authored: Tue Mar 14 21:43:22 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Mar 14 21:43:22 2017 +0100

----------------------------------------------------------------------
 .../java/freemarker/core/SQLTimeZoneTest.java    |  2 ++
 src/test/java/freemarker/test/TemplateTest.java  | 19 +++++++++++++++++++
 2 files changed, 21 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/649d85d1/src/test/java/freemarker/core/SQLTimeZoneTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/SQLTimeZoneTest.java b/src/test/java/freemarker/core/SQLTimeZoneTest.java
index 3ef114c..b4002f6 100644
--- a/src/test/java/freemarker/core/SQLTimeZoneTest.java
+++ b/src/test/java/freemarker/core/SQLTimeZoneTest.java
@@ -135,6 +135,7 @@ public class SQLTimeZoneTest extends TemplateTest {
         TimeZone.setDefault(GMT_P02);
         try {
             Configuration cfg = getConfiguration();
+            cfg.unsetTimeZone();
             assertNull(cfg.getSQLDateAndTimeTimeZone());
             assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
             
@@ -150,6 +151,7 @@ public class SQLTimeZoneTest extends TemplateTest {
         TimeZone.setDefault(GMT_P02);
         try {
             Configuration cfg = getConfiguration();
+            cfg.unsetTimeZone();
             cfg.setSQLDateAndTimeTimeZone(GMT_P02);
             
             assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/649d85d1/src/test/java/freemarker/test/TemplateTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/test/TemplateTest.java b/src/test/java/freemarker/test/TemplateTest.java
index 4747ed0..99e2db1 100644
--- a/src/test/java/freemarker/test/TemplateTest.java
+++ b/src/test/java/freemarker/test/TemplateTest.java
@@ -25,9 +25,12 @@ import static org.junit.Assert.*;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
+import java.util.TimeZone;
 
 import org.apache.commons.io.IOUtils;
 import org.junit.Ignore;
@@ -59,6 +62,7 @@ public abstract class TemplateTest {
             try {
                 configuration = createConfiguration();
                 addCommonTemplates();
+                applyEnvironmentIndependentDefaults();
             } catch (Exception e) {
                 throw new RuntimeException("Failed to set up configuration for the test", e);
             }
@@ -66,6 +70,21 @@ public abstract class TemplateTest {
         return configuration;
     }
 
+    /**
+     * Ensure that the configuration settings don't depend on the machine that runs the test.
+     */
+    private void applyEnvironmentIndependentDefaults() {
+        if (!configuration.isLocaleExplicitlySet()) {
+            configuration.setLocale(Locale.US);
+        }
+        if (!configuration.isDefaultEncodingExplicitlySet()) {
+            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
+        }
+        if (!configuration.isTimeZoneExplicitlySet()) {
+            configuration.setTimeZone(TimeZone.getTimeZone("GMT+1"));
+        }
+    }
+
     protected final void setConfiguration(Configuration configuration) {
         this.configuration = configuration;
     }


[07/10] incubator-freemarker git commit: Added copyright headers to .git* files.

Posted by dd...@apache.org.
Added copyright headers to .git* files.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/ca52e2d0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/ca52e2d0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/ca52e2d0

Branch: refs/heads/2.3
Commit: ca52e2d05b0672b9896cdc1c1bf918ec999eb267
Parents: 5198486
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 13:05:02 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 13:05:02 2017 +0100

----------------------------------------------------------------------
 .gitattributes | 17 +++++++++++++++++
 .gitignore     | 17 +++++++++++++++++
 2 files changed, 34 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ca52e2d0/.gitattributes
----------------------------------------------------------------------
diff --git a/.gitattributes b/.gitattributes
index 57798ba..0ee4c3a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,18 @@
+# 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.
+
 *	text=auto

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ca52e2d0/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 28532ff..037de7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,20 @@
+# 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.
+
 /.ivy/
 /.bin/
 /build/


[09/10] incubator-freemarker git commit: Build: Added "test" to the dist task.

Posted by dd...@apache.org.
Build: Added "test" to the dist task.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/36305d0c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/36305d0c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/36305d0c

Branch: refs/heads/2.3
Commit: 36305d0c5dddf4bbe1fd9e45472b29b4f0fedae5
Parents: ca52e2d
Author: ddekany <dd...@apache.org>
Authored: Wed Mar 15 13:30:47 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Mar 15 13:30:47 2017 +0100

----------------------------------------------------------------------
 build.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/36305d0c/build.xml
----------------------------------------------------------------------
diff --git a/build.xml b/build.xml
index 4e1f979..d81a9b9 100644
--- a/build.xml
+++ b/build.xml
@@ -655,7 +655,7 @@
   </target>
   
   <target name="_dist"
-    depends="jar, javadoc, manualOffline"
+    depends="test, jar, javadoc, manualOffline"
   >
     <delete dir="${dist.dir}" />