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 2019/07/14 22:34:17 UTC

[freemarker] branch 2.3-gae updated (f00d8c2 -> 926f33e)

This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a change to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git.


    from f00d8c2  Merge pull request #59 from vocatan/2.3-gae
     new a1fd6ff  Some more tests for the fallbackOnNullLoopVariable setting.
     new 926f33e  (Javadoc improvements, related to LocalContext and fallbackOnNullLoopVariable)

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/main/java/freemarker/core/Environment.java     | 61 ++++-----------
 src/main/java/freemarker/core/LocalContext.java    | 31 ++++++--
 src/main/java/freemarker/core/Macro.java           | 16 +---
 .../java/freemarker/template/Configuration.java    | 90 ++++------------------
 .../java/freemarker/core/NullTransparencyTest.java | 23 +++---
 .../freemarker/template/ConfigurationTest.java     | 81 +++++++------------
 6 files changed, 90 insertions(+), 212 deletions(-)


[freemarker] 02/02: (Javadoc improvements, related to LocalContext and fallbackOnNullLoopVariable)

Posted by dd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git

commit 926f33efdd5cad3e04dc2dd80ddfda1de39df712
Author: ddekany <dd...@apache.org>
AuthorDate: Mon Jul 15 00:33:19 2019 +0200

    (Javadoc improvements, related to LocalContext and fallbackOnNullLoopVariable)
---
 src/main/java/freemarker/core/Environment.java     | 61 ++++-----------
 src/main/java/freemarker/core/LocalContext.java    | 31 ++++++--
 src/main/java/freemarker/core/Macro.java           | 16 +---
 .../java/freemarker/template/Configuration.java    | 90 ++++------------------
 4 files changed, 53 insertions(+), 145 deletions(-)

diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 9553d5b..aba344c 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -19,64 +19,30 @@
 
 package freemarker.core;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.text.Collator;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import freemarker.cache.TemplateNameFormat;
 import freemarker.cache._CacheAPI;
 import freemarker.ext.beans.BeansWrapper;
 import freemarker.log.Logger;
-import freemarker.template.Configuration;
-import freemarker.template.MalformedTemplateNameException;
-import freemarker.template.ObjectWrapper;
-import freemarker.template.SimpleHash;
-import freemarker.template.SimpleSequence;
-import freemarker.template.Template;
-import freemarker.template.TemplateCollectionModel;
-import freemarker.template.TemplateDateModel;
-import freemarker.template.TemplateDirectiveBody;
-import freemarker.template.TemplateDirectiveModel;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateExceptionHandler;
-import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateHashModelEx;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateModelIterator;
-import freemarker.template.TemplateNodeModel;
-import freemarker.template.TemplateNumberModel;
-import freemarker.template.TemplateScalarModel;
-import freemarker.template.TemplateSequenceModel;
-import freemarker.template.TemplateTransformModel;
-import freemarker.template.TransformControl;
-import freemarker.template._TemplateAPI;
+import freemarker.template.*;
 import freemarker.template.utility.DateUtil;
 import freemarker.template.utility.DateUtil.DateToISO8601CalendarFactory;
 import freemarker.template.utility.NullWriter;
 import freemarker.template.utility.StringUtil;
 import freemarker.template.utility.UndeclaredThrowableException;
 
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.text.Collator;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.*;
+
 /**
  * Object that represents the runtime environment during template processing. For every invocation of a
  * <tt>Template.process()</tt> method, a new instance of this object is created, and then discarded when
@@ -708,7 +674,6 @@ public final class Environment extends Configurable {
         }
 
         public TemplateModel getLocalVariable(String name) throws TemplateModelException {
-            // TODO [lambda] Do not allow fallback (i.e., introduce untransparent null-s)
             return name.equals(lambdaArgName) ? lambdaArgValue : null;
         }
 
diff --git a/src/main/java/freemarker/core/LocalContext.java b/src/main/java/freemarker/core/LocalContext.java
index cc90e0a..734b6cc 100644
--- a/src/main/java/freemarker/core/LocalContext.java
+++ b/src/main/java/freemarker/core/LocalContext.java
@@ -19,20 +19,35 @@
 
 package freemarker.core;
 
-import java.util.Collection;
-
+import freemarker.template.Configuration;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
 
-/**
-  * An interface that represents a local context. This is used as the abstraction for  
-  * the context of a Macro invocation, a loop, or the nested block call from within 
-  * a macro.
-  * <a href="mailto:jon@revusky.com">Jonathan Revusky</a>
-  */
+import java.util.Collection;
 
+/**
+ * Represents a local context (a set of local variables); should be internal, but left public for backward
+ * compatibility. This is used as the abstraction for accessing the local variables of a macro/function invocation,
+ * the loops variables of {#code #list}, the nested content variables of a macro call, or the arguments to a lambda
+ * expression.
+ */
 public interface LocalContext {
+
+    /**
+     * @return {@code null} if the variable doesn't exit. Since 2.3.29, if this context represents loop variables, this
+     *     is possibly {@code freemarker.core.NullTemplateModel.INSTANCE} (an internal class) when
+     *     {@link Configuration#setFallbackOnNullLoopVariable(boolean)} was set to {@code false}, in which
+     *     case the caller must not fall back to higher scopes to find the variable, and treat the value as
+     *     {@code null} in other respects. While this is in theory an incompatible change in 2.3.29, it's not a problem,
+     *     it's very unlikely (hopefully impossible with published API-s) that user code gets a {@link LocalContext}
+     *     that stores loop variables, and also because by default
+     *     {@link Configuration#setFallbackOnNullLoopVariable(boolean)} is {@code true}.
+     */
     TemplateModel getLocalVariable(String name) throws TemplateModelException;
+
+    /**
+     * The names of the local variables that were declared or set in this context.
+     */
     Collection getLocalVariableNames() throws TemplateModelException;
     
 }
diff --git a/src/main/java/freemarker/core/Macro.java b/src/main/java/freemarker/core/Macro.java
index 7829c76..a0e355f 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -19,17 +19,9 @@
 
 package freemarker.core;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
+import freemarker.template.*;
 
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateModelIterator;
-import freemarker.template.TemplateScalarModel;
+import java.util.*;
 
 /**
  * An element representing a macro declaration.
@@ -242,10 +234,6 @@ public final class Macro extends TemplateElement implements TemplateModel {
             }
         }
 
-        /**
-         * @return the local variable of the given name
-         * or null if it doesn't exist.
-         */ 
         public TemplateModel getLocalVariable(String name) throws TemplateModelException {
              return localVars.get(name);
         }
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index 21e02a1..1149879 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -19,6 +19,14 @@
 
 package freemarker.template;
 
+import freemarker.cache.*;
+import freemarker.cache.TemplateCache.MaybeMissingTemplate;
+import freemarker.core.*;
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.ext.beans.BeansWrapperBuilder;
+import freemarker.log.Logger;
+import freemarker.template.utility.*;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.Writer;
@@ -26,79 +34,11 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.URLConnection;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 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;
 
-import freemarker.cache.CacheStorage;
-import freemarker.cache.ClassTemplateLoader;
-import freemarker.cache.FileTemplateLoader;
-import freemarker.cache.MruCacheStorage;
-import freemarker.cache.MultiTemplateLoader;
-import freemarker.cache.SoftCacheStorage;
-import freemarker.cache.TemplateCache;
-import freemarker.cache.TemplateCache.MaybeMissingTemplate;
-import freemarker.cache.TemplateConfigurationFactory;
-import freemarker.cache.TemplateLoader;
-import freemarker.cache.TemplateLookupContext;
-import freemarker.cache.TemplateLookupStrategy;
-import freemarker.cache.TemplateNameFormat;
-import freemarker.cache.URLTemplateLoader;
-import freemarker.core.BugException;
-import freemarker.core.CSSOutputFormat;
-import freemarker.core.CombinedMarkupOutputFormat;
-import freemarker.core.Configurable;
-import freemarker.core.Environment;
-import freemarker.core.HTMLOutputFormat;
-import freemarker.core.JSONOutputFormat;
-import freemarker.core.JavaScriptOutputFormat;
-import freemarker.core.MarkupOutputFormat;
-import freemarker.core.OutputFormat;
-import freemarker.core.ParseException;
-import freemarker.core.ParserConfiguration;
-import freemarker.core.PlainTextOutputFormat;
-import freemarker.core.RTFOutputFormat;
-import freemarker.core.TemplateConfiguration;
-import freemarker.core.TemplateMarkupOutputModel;
-import freemarker.core.UndefinedOutputFormat;
-import freemarker.core.UnregisteredOutputFormatException;
-import freemarker.core.XHTMLOutputFormat;
-import freemarker.core.XMLOutputFormat;
-import freemarker.core._CoreAPI;
-import freemarker.core._DelayedJQuote;
-import freemarker.core._MiscTemplateException;
-import freemarker.core._ObjectBuilderSettingEvaluator;
-import freemarker.core._SettingEvaluationEnvironment;
-import freemarker.core._SortedArraySet;
-import freemarker.core._UnmodifiableCompositeSet;
-import freemarker.ext.beans.BeansWrapper;
-import freemarker.ext.beans.BeansWrapperBuilder;
-import freemarker.log.Logger;
-import freemarker.template.utility.CaptureOutput;
-import freemarker.template.utility.ClassUtil;
-import freemarker.template.utility.Constants;
-import freemarker.template.utility.HtmlEscape;
-import freemarker.template.utility.NormalizeNewlines;
-import freemarker.template.utility.NullArgumentException;
-import freemarker.template.utility.SecurityUtilities;
-import freemarker.template.utility.StandardCompress;
-import freemarker.template.utility.StringUtil;
-import freemarker.template.utility.XmlEscape;
-
 /**
  * <b>The main entry point into the FreeMarker API</b>; encapsulates the configuration settings of FreeMarker,
  * also serves as a central template-loading and caching service.
@@ -2594,17 +2534,17 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     }
 
     /**
-     * Specifies the behavior when reading a loop variable (like {@code i} in {@code <#list items as i>}) that's
-     * {@code null} (missing); if {@code true}, FreeMarker will look for a variable with the same name in higher
-     * variable scopes, or if {@code false} the variable will be simply {@code null} (missing).
-     * For backward compatibility the default is {@code true}. The recommended value for new projects is
+     * Specifies the behavior when reading a loop variable (like {@code i} in {@code <#list items as i>}, or in
+     * {@code <@myMacro items; i>}) that's {@code null} (missing); if {@code true}, FreeMarker will look for a variable
+     * with the same name in higher variable scopes, or if {@code false} the variable will be simply {@code null}
+     * (missing). For backward compatibility the default is {@code true}. The recommended value for new projects is
      * {@code false}, as otherwise adding new variables to higher scopes (typically to the data-model) can
      * unintentionally change the behavior of templates. You have to be quite unlucky for that to happen though:
      * The newly added variable has to have the same name as the loop variable, and there must be some null (missing)
      * values in what you loop through.
      *
-     * <p>Note that this doesn't influence the behavior of lambdas, like {@code items?filter(i -> i?hasContent)},
-     * because reading lambda arguments never fall back to higher scopes.
+     * <p>This setting doesn't influence the behavior of lambdas, like {@code items?filter(i -> i?hasContent)}, as they
+     * never had this problem. Reading a lambda argument never falls back to higher scopes.
      *
      * @since 2.3.29
      */


[freemarker] 01/02: Some more tests for the fallbackOnNullLoopVariable setting.

Posted by dd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git

commit a1fd6ff225df1e724df5e474043d4916af2cc744
Author: ddekany <dd...@apache.org>
AuthorDate: Sun Jul 14 23:36:18 2019 +0200

    Some more tests for the fallbackOnNullLoopVariable setting.
---
 .../java/freemarker/core/NullTransparencyTest.java | 23 +++---
 .../freemarker/template/ConfigurationTest.java     | 81 +++++++---------------
 2 files changed, 37 insertions(+), 67 deletions(-)

diff --git a/src/test/java/freemarker/core/NullTransparencyTest.java b/src/test/java/freemarker/core/NullTransparencyTest.java
index 24a9792..e9d63ee 100644
--- a/src/test/java/freemarker/core/NullTransparencyTest.java
+++ b/src/test/java/freemarker/core/NullTransparencyTest.java
@@ -19,19 +19,14 @@
 
 package freemarker.core;
 
-import static org.junit.Assert.*;
+import freemarker.template.TemplateException;
+import freemarker.test.TemplateTest;
+import org.junit.Test;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
-import org.junit.Test;
-
-import freemarker.template.TemplateException;
-import freemarker.test.TemplateTest;
+import static org.junit.Assert.assertTrue;
 
 public class NullTransparencyTest extends TemplateTest {
 
@@ -91,18 +86,22 @@ public class NullTransparencyTest extends TemplateTest {
     protected void testLoopVariables(String expectedFallback) throws IOException, TemplateException {
         assertOutput("<#list list as it>${it!'null'}<#sep>, </#list>",
                 "a, " + expectedFallback + ", b");
+        assertOutput("<#list list><#items as it>${it!'null'}<#sep>, </#items></#list>",
+                "a, " + expectedFallback + ", b");
 
         assertOutput("<#list map?values as it>${it!'null'}<#sep>, </#list>",
                 "av, bv, " + expectedFallback);
         assertOutput("<#list map as k, it>${k!'null'}=${it!'null'}<#sep>, </#list>",
                 "ak=av, null=bv, ck=" + expectedFallback);
+        assertOutput("<#list map><#items as k, it>${k!'null'}=${it!'null'}<#sep>, </#items></#list>",
+                "ak=av, null=bv, ck=" + expectedFallback);
 
         assertOutput("<#list map?keys as it>${it!'null'}<#sep>, </#list>",
                 "ak, " + expectedFallback + ", ck");
         assertOutput("<#list map as it, v>${it!'null'}=${v!'null'}<#sep>, </#list>",
                 "ak=av, " + expectedFallback + "=bv, ck=null");
-
-        // TODO #item
+        assertOutput("<#list map><#items as it, v>${it!'null'}=${v!'null'}<#sep>, </#items></#list>",
+                "ak=av, " + expectedFallback + "=bv, ck=null");
 
         assertOutput("" +
                 "<#macro loop><#nested 1>, <#nested totallyMissing></#macro>\n" +
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 3cf8c8b..80c2805 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -19,72 +19,28 @@
 
 package freemarker.template;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
-import org.junit.Test;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import freemarker.cache.CacheStorageWithGetSize;
-import freemarker.cache.FileTemplateLoader;
-import freemarker.cache.NullCacheStorage;
-import freemarker.cache.SoftCacheStorage;
-import freemarker.cache.StringTemplateLoader;
-import freemarker.cache.StrongCacheStorage;
-import freemarker.cache.TemplateCache;
-import freemarker.cache.TemplateLookupContext;
-import freemarker.cache.TemplateLookupResult;
-import freemarker.cache.TemplateLookupStrategy;
-import freemarker.cache.TemplateNameFormat;
-import freemarker.core.BaseNTemplateNumberFormatFactory;
-import freemarker.core.CombinedMarkupOutputFormat;
-import freemarker.core.Configurable;
+import freemarker.cache.*;
+import freemarker.core.*;
 import freemarker.core.Configurable.SettingValueAssignmentException;
 import freemarker.core.Configurable.UnknownSettingException;
-import freemarker.core.ConfigurableTest;
-import freemarker.core.CustomHTMLOutputFormat;
-import freemarker.core.DefaultTruncateBuiltinAlgorithm;
-import freemarker.core.DummyOutputFormat;
-import freemarker.core.Environment;
-import freemarker.core.EpochMillisDivTemplateDateFormatFactory;
-import freemarker.core.EpochMillisTemplateDateFormatFactory;
-import freemarker.core.HTMLOutputFormat;
-import freemarker.core.HexTemplateNumberFormatFactory;
-import freemarker.core.MarkupOutputFormat;
-import freemarker.core.OptInTemplateClassResolver;
-import freemarker.core.OutputFormat;
-import freemarker.core.ParseException;
-import freemarker.core.RTFOutputFormat;
-import freemarker.core.TemplateClassResolver;
-import freemarker.core.TemplateDateFormatFactory;
-import freemarker.core.TemplateNumberFormatFactory;
-import freemarker.core.UndefinedOutputFormat;
-import freemarker.core.UnregisteredOutputFormatException;
-import freemarker.core.XHTMLOutputFormat;
-import freemarker.core.XMLOutputFormat;
-import freemarker.core._CoreStringUtils;
 import freemarker.ext.beans.BeansWrapperBuilder;
 import freemarker.ext.beans.StringModel;
 import freemarker.template.utility.DateUtil;
 import freemarker.template.utility.NullArgumentException;
 import freemarker.template.utility.NullWriter;
 import junit.framework.TestCase;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.util.*;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
 
 public class ConfigurationTest extends TestCase {
 
@@ -1882,6 +1838,21 @@ public class ConfigurationTest extends TestCase {
     }
 
     @Test
+    public void testFallbackOnNullLoopVariable() throws TemplateException {
+        Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
+        assertTrue(cfg.getFallbackOnNullLoopVariable());
+
+        cfg.setSetting("fallback_on_null_loop_variable", "false");
+        assertFalse(cfg.getFallbackOnNullLoopVariable());
+
+        cfg.setSetting("fallback_on_null_loop_variable", "true");
+        assertTrue(cfg.getFallbackOnNullLoopVariable());
+
+        cfg.setSetting("fallbackOnNullLoopVariable", "NO");
+        assertFalse(cfg.getFallbackOnNullLoopVariable());
+    }
+
+    @Test
     public void testGetSettingNamesAreSorted() throws Exception {
         Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
         for (boolean camelCase : new boolean[] { false, true }) {