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 2016/06/08 21:09:23 UTC

[3/3] incubator-freemarker git commit: Added duplicate filtering to setAutoIncludes(List), if called on non-Configuration or if IcI >= 2.3.25. Allowing duplicates was an oversight in earlier versions.

Added duplicate filtering to setAutoIncludes(List), if called on non-Configuration or if IcI >= 2.3.25. Allowing duplicates was an oversight in earlier versions.


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

Branch: refs/heads/2.3-gae
Commit: 6c335728fd27857f0e1fd59d206c346fcaa922f7
Parents: 7495228
Author: ddekany <dd...@apache.org>
Authored: Wed Jun 8 23:09:08 2016 +0200
Committer: ddekany <dd...@apache.org>
Committed: Wed Jun 8 23:09:08 2016 +0200

----------------------------------------------------------------------
 src/main/java/freemarker/core/Configurable.java | 24 +++++-----
 .../java/freemarker/template/Configuration.java | 31 +++++++++++--
 .../core/AutoImportAndIncludeTest.java          | 47 ++++++++++++++++----
 .../core/TemplateConfigurationTest.java         |  3 +-
 4 files changed, 81 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6c335728/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 fbee5a6..d71b64f 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -1763,29 +1763,29 @@ public class Configurable {
      * the auto-includes, hence the namespace variables are accessible for the auto-included templates.
      * 
      * <p>
-     * You should avoid adding the same auto-include for multiple times, as you can easily end up including the same
-     * template for multiple times. Calling {@link #addAutoInclude(String)} with an already added template name will
-     * just move that to the end of the auto-include list, but the same won't happen when using
-     * {@link #setAutoIncludes(List)}, nor when the same string occurs on a different {@link Configurable} level.
+     * Calling {@link #addAutoInclude(String)} with an already added template name will just move that to the end of the
+     * auto-include list (within the same {@link Configurable} level). This works even if the same template name appears
+     * on different {@link Configurable} levels, in which case only the inclusion on the lowest (child) level will be
+     * executed.
      * 
      * @see #setAutoIncludes(List)
      */
     public void addAutoInclude(String templateName) {
-        addAutoInclude(templateName, true);
+        addAutoInclude(templateName, false);
     }
 
     /**
-     * @param removeDuplicate
+     * @param keepDuplicate
      *            Used for emulating legacy glitch, where duplicates weren't removed if the inclusion was added via
-     *            {@link #setAutoIncludes(List)}, but were if it was added via {@link #addAutoInclude(String)}.
+     *            {@link #setAutoIncludes(List)}.
      */
-    private void addAutoInclude(String templateName, boolean removeDuplicate) {
+    private void addAutoInclude(String templateName, boolean keepDuplicate) {
         // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration
         synchronized (this) {
             if (autoIncludes == null) {
                 initAutoIncludesList();
             } else {
-                if (removeDuplicate) {
+                if (!keepDuplicate) {
                     autoIncludes.remove(templateName);
                 }
             }
@@ -1799,6 +1799,9 @@ public class Configurable {
     
     /**
      * Removes all auto-includes, then calls {@link #addAutoInclude(String)} for each {@link List} items.
+     * 
+     * <p>Before {@linkplain Configuration#Configuration(Version) incompatible improvements} 2.3.25 it doesn't filter
+     * out duplicates from the list if this method was called on a {@link Configuration} instance.
      */
     public void setAutoIncludes(List templateNames) {
         NullArgumentException.check("templateNames", templateNames);
@@ -1811,7 +1814,8 @@ public class Configurable {
                 if (!(templateName instanceof String)) {
                     throw new IllegalArgumentException("List items must be String-s.");
                 }
-                addAutoInclude((String) templateName, false);
+                addAutoInclude((String) templateName, this instanceof Configuration && ((Configuration) this)
+                        .getIncompatibleImprovements().intValue() < _TemplateAPI.VERSION_INT_2_3_25);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6c335728/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 07f921a..9565258 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -426,6 +426,9 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     /** FreeMarker version 2.3.24 (an {@link #Configuration(Version) incompatible improvements break-point}) */
     public static final Version VERSION_2_3_24 = new Version(2, 3, 24);
 
+    /** FreeMarker version 2.3.25 (an {@link #Configuration(Version) incompatible improvements break-point}) */
+    public static final Version VERSION_2_3_25 = new Version(2, 3, 25);
+    
     /** The default of {@link #getIncompatibleImprovements()}, currently {@link #VERSION_2_3_0}. */
     public static final Version DEFAULT_INCOMPATIBLE_IMPROVEMENTS = Configuration.VERSION_2_3_0;
     /** @deprecated Use {@link #DEFAULT_INCOMPATIBLE_IMPROVEMENTS} instead. */
@@ -820,6 +823,16 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
      *          (They shouldn't implement either, but this is historical heritage.)
      *     </ul>
      *   </li>
+     *   <li><p>
+     *     2.3.25 (or higher):
+     *     <ul>
+     *       <li><p>
+     *          When calling {@link Configurable#setAutoIncludes(List)} on a {@link Configuration}, it filters out
+     *          duplicates from the list, similarly as repeatedly calling {@link Configurable#addAutoInclude(String)}
+     *          would, hence avoiding repeated inclusions. Calling {@link Configurable#setAutoIncludes(List)} on other
+     *          {@link Configurable}-s always do this filtering regardless of the incompatible improvements setting. 
+     *     </ul>
+     *   </li>
      * </ul>
      * 
      * @throws IllegalArgumentException
@@ -3095,18 +3108,28 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     
     private void doAutoIncludes(Environment env, Template t) throws TemplateException, IOException,
             TemplateNotFoundException, MalformedTemplateNameException, ParseException {
+        // We can't store autoIncludes in LinkedHashSet-s because setAutoIncludes(List) allows duplicates,
+        // unfortunately. Yet we have to prevent duplicates among Configuration levels, with the lowest levels having
+        // priority. So we build some Set-s to do that, but we avoid the most common cases where they aren't needed.
+        
+        List<String> tAutoIncludes = t.getAutoIncludesWithoutFallback();
+        List<String> envAutoIncludes = env.getAutoIncludesWithoutFallback();
+        
         for (String templateName : getAutoIncludesWithoutFallback()) {
-            env.include(getTemplate(templateName, env.getLocale()));
+            if ((tAutoIncludes == null || !tAutoIncludes.contains(templateName))
+                    && (envAutoIncludes == null || !envAutoIncludes.contains(templateName))) {
+                env.include(getTemplate(templateName, env.getLocale()));
+            }
         }
         
-        List<String> tAutoIncludes = t.getAutoIncludesWithoutFallback();
         if (tAutoIncludes != null) {
             for (String templateName : tAutoIncludes) {
-                env.include(getTemplate(templateName, env.getLocale()));
+                if (envAutoIncludes == null || !envAutoIncludes.contains(templateName)) {
+                    env.include(getTemplate(templateName, env.getLocale()));
+                }
             }
         }
         
-        List<String> envAutoIncludes = env.getAutoIncludesWithoutFallback();
         if (envAutoIncludes != null) {
             for (String templateName : envAutoIncludes) {
                 env.include(getTemplate(templateName, env.getLocale()));

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6c335728/src/test/java/freemarker/core/AutoImportAndIncludeTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/AutoImportAndIncludeTest.java b/src/test/java/freemarker/core/AutoImportAndIncludeTest.java
index 91faa4b..c813e69 100644
--- a/src/test/java/freemarker/core/AutoImportAndIncludeTest.java
+++ b/src/test/java/freemarker/core/AutoImportAndIncludeTest.java
@@ -160,9 +160,9 @@ public class AutoImportAndIncludeTest extends TemplateTest {
             assertEquals("T2;T3;In main: t2;t3;", sw.toString());
         }
     }
-    
+
     @Test
-    public void test3LayerIncludesNoClashes2() throws Exception {
+    public void test3LayerIncludeClashes() throws Exception {
         Configuration cfg = getConfiguration();
         cfg.addAutoInclude("t1.ftl");
         cfg.addAutoInclude("t2.ftl");
@@ -180,17 +180,44 @@ public class AutoImportAndIncludeTest extends TemplateTest {
             env.addAutoInclude("t3.ftl");
     
             env.process();
-            assertEquals("T1;T2;T3;T2;T3;In main: t1;t2;t3;t2;t3;", sw.toString());
+            assertEquals("T1;T2;T3;In main: t1;t2;t3;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main2.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T1;T2;T3;In main2: t1;t2;t3;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+    
+            env.process();
+            assertEquals("T1;T3;T2;In main: t1;t3;t2;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t1.ftl");
+    
+            env.process();
+            assertEquals("T3;T2;T1;In main: t3;t2;t1;", sw.toString());
         }
     }
-
+    
     @Test
-    public void test3LayerIncludesClashes() throws Exception {
+    public void test3LayerIncludesClashes2() throws Exception {
         Configuration cfg = getConfiguration();
         cfg.addAutoInclude("t1.ftl");
-        cfg.addAutoInclude("t3.ftl");
-        cfg.addAutoInclude("t2.ftl");
-        cfg.addAutoInclude("t3.ftl");
+        cfg.addAutoInclude("t1.ftl");
 
         TemplateConfiguration tc = new TemplateConfiguration();
         tc.addAutoInclude("t2.ftl");
@@ -204,9 +231,11 @@ public class AutoImportAndIncludeTest extends TemplateTest {
             Environment env = t.createProcessingEnvironment(null, sw);
             env.addAutoInclude("t3.ftl");
             env.addAutoInclude("t3.ftl");
+            env.addAutoInclude("t1.ftl");
+            env.addAutoInclude("t1.ftl");
     
             env.process();
-            assertEquals("T1;T2;T3;T2;T3;In main: t1;t2;t3;t2;t3;", sw.toString());
+            assertEquals("T2;T3;T1;In main: t2;t3;t1;", sw.toString());
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6c335728/src/test/java/freemarker/core/TemplateConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/TemplateConfigurationTest.java b/src/test/java/freemarker/core/TemplateConfigurationTest.java
index 5b05e48..861d1f7 100644
--- a/src/test/java/freemarker/core/TemplateConfigurationTest.java
+++ b/src/test/java/freemarker/core/TemplateConfigurationTest.java
@@ -307,7 +307,8 @@ public class TemplateConfigurationTest {
                 propDesc2.getWriteMethod().invoke(tc2, value2);
 
                 tc1.merge(tc2);
-                if (propDesc1.getName().equals(propDesc2.getName()) && value1 instanceof List) {
+                if (propDesc1.getName().equals(propDesc2.getName()) && value1 instanceof List
+                        && !propDesc1.getName().equals("autoIncludes")) {
                     assertEquals("For " + propDesc1.getName(),
                             ListUtils.union((List) value1, (List) value1), propDesc1.getReadMethod().invoke(tc1));
                 } else { // Values of the same setting merged