FREEMARKER-63: Added isNestedContentSupported() to templateDirectiveModel
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/5bd19ade Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/5bd19ade Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/5bd19ade Branch: refs/heads/3 Commit: 5bd19adeb8dd24cde34987c4724c7a5d5d227f52 Parents: 589d9b8 Author: ddekany <ddek...@apache.org> Authored: Sun Jul 30 23:07:29 2017 +0200 Committer: ddekany <ddek...@apache.org> Committed: Sun Jul 30 23:07:29 2017 +0200 ---------------------------------------------------------------------- FM3-CHANGE-LOG.txt | 2 ++ .../freemarker/core/DirectiveCallPlaceTest.java | 16 ++++++++++++++++ .../core/EnvironmentGetTemplateVariantsTest.java | 6 ++++++ .../core/TemplateCallableModelTest.java | 4 ++++ .../core/TheadInterruptingSupportTest.java | 16 +++++++++++++++- .../core/userpkg/AllFeaturesDirective.java | 6 ++++++ .../core/userpkg/NamedVarargsOnlyDirective.java | 7 +++++++ .../userpkg/PositionalVarargsOnlyDirective.java | 7 +++++++ .../core/userpkg/TwoNamedParamsDirective.java | 8 ++++++-- .../userpkg/TwoNestedContentParamsDirective.java | 6 ++++++ .../userpkg/TwoPositionalParamsDirective.java | 8 ++++++-- .../core/userpkg/UpperCaseDirective.java | 6 ++++++ .../core/valueformat/NumberFormatTest.java | 5 +++++ .../core/templatesuite/expected/interpret.txt | 4 +--- .../core/templatesuite/templates/interpret.ftl | 7 ++++--- .../freemarker/core/ASTDynamicTopLevelCall.java | 18 +++++++++++++----- .../freemarker/core/BuiltInsForStringsMisc.java | 6 +++++- .../core/model/TemplateDirectiveModel.java | 13 +++++++++++++ .../apache/freemarker/servlet/IncludePage.java | 5 +++++ .../jsp/CustomTagAndELFunctionCombiner.java | 10 ++++++++++ .../servlet/jsp/SimpleTagDirectiveModel.java | 5 +++++ .../freemarker/servlet/jsp/TagDirectiveModel.java | 5 +++++ .../test/templateutil/AssertDirective.java | 5 +++++ .../test/templateutil/AssertEqualsDirective.java | 14 ++++++++++---- .../test/templateutil/AssertFailsDirective.java | 14 ++++++++++---- .../test/templateutil/NoOutputDirective.java | 6 ++++++ 26 files changed, 184 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/FM3-CHANGE-LOG.txt ---------------------------------------------------------------------- diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt index 6b347e5..938f9bf 100644 --- a/FM3-CHANGE-LOG.txt +++ b/FM3-CHANGE-LOG.txt @@ -108,6 +108,8 @@ Node: Changes already mentioned above aren't repeated here! of the `execute` method. - ?isTransform was removed (as there are no transforms anymore). Converter note: The template converter tool replaces it with ?isDirective +- The directive returned by `?interpret` doesn't allow nested content anymore. (It wasn't useful earlier either; + the nested content was simply executed after the interpreted string.) Java API changes ================ http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java index 94cd199..f959b1d 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java @@ -142,6 +142,11 @@ public class DirectiveCallPlaceTest extends TemplateTest { return ArgumentArrayLayout.PARAMETERLESS; } + @Override + public boolean isNestedContentSupported() { + return true; + } + protected abstract Class getTextConversionIdentity(); private String convertBodyText(CallPlace callPlace, Environment env) throws TemplateException, @@ -207,6 +212,11 @@ public class DirectiveCallPlaceTest extends TemplateTest { return ArgumentArrayLayout.PARAMETERLESS; } + @Override + public boolean isNestedContentSupported() { + return true; + } + private String getTemplateSourceName(CallPlace callPlace) { return callPlace.getTemplate().getSourceName(); } @@ -239,6 +249,12 @@ public class DirectiveCallPlaceTest extends TemplateTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + @Override + public boolean isNestedContentSupported() { + return true; + } + } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java index 40f7c63..10205e9 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java @@ -211,6 +211,12 @@ public class EnvironmentGetTemplateVariantsTest extends TemplateTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + + @Override + public boolean isNestedContentSupported() { + return false; + } }); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java index a51c657..b7d55f5 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java @@ -167,6 +167,10 @@ public class TemplateCallableModelTest extends TemplateTest { assertErrorContains("<@tncp ; i>${i}</@>", " 1 ", "\"i\"", " 2 "); assertOutput("<@tncp ; i, j>${i} ${j}</@>", "1 2"); assertErrorContains("<@tncp ; i, j, k>${i}</@>", " 3 ", "\"i\", \"j\", \"k\"", " 2 "); + + assertOutput("<@p></@p>", + "#p(p1=null, p2=null)"); + assertErrorContains("<@p> </@p>", "Nested content", "not supported"); } @Test http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java index 2ab270a..a6b01ac 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java @@ -133,10 +133,14 @@ public class TheadInterruptingSupportTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return false; + } } public class CustomLoopDirective implements TemplateDirectiveModel { - @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { @@ -150,6 +154,11 @@ public class TheadInterruptingSupportTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return true; + } } public class SleepDirective implements TemplateDirectiveModel { @@ -168,6 +177,11 @@ public class TheadInterruptingSupportTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return false; + } } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java index e3be217..24a3a4e 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java @@ -123,4 +123,10 @@ public class AllFeaturesDirective extends TestTemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + @Override + public boolean isNestedContentSupported() { + return true; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java index aa69e8f..f978dbe 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java @@ -56,4 +56,11 @@ public class NamedVarargsOnlyDirective extends TestTemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + + @Override + public boolean isNestedContentSupported() { + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java index cc3f9d8..b9d2b92 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java @@ -54,4 +54,11 @@ public class PositionalVarargsOnlyDirective extends TestTemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + + @Override + public boolean isNestedContentSupported() { + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java index dbff203..b4b85d3 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.Writer; import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.NestedContentNotSupportedException; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.ArgumentArrayLayout; import org.apache.freemarker.core.model.CallPlace; @@ -55,7 +54,6 @@ public class TwoNamedParamsDirective extends TestTemplateDirectiveModel { @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - NestedContentNotSupportedException.check(callPlace); out.write("#n("); printParam(N1_ARG_NAME, args[N1_ARG_IDX], out, true); printParam(N2_ARG_NAME, args[N2_ARG_IDX], out); @@ -66,4 +64,10 @@ public class TwoNamedParamsDirective extends TestTemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + @Override + public boolean isNestedContentSupported() { + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java index eee1978..ff47315 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java @@ -50,4 +50,10 @@ public class TwoNestedContentParamsDirective extends TestTemplateDirectiveModel public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return true; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java index 52fe77e..4bd671e 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.Writer; import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.NestedContentNotSupportedException; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.ArgumentArrayLayout; import org.apache.freemarker.core.model.CallPlace; @@ -44,7 +43,6 @@ public class TwoPositionalParamsDirective extends TestTemplateDirectiveModel { @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - NestedContentNotSupportedException.check(callPlace); out.write("#p("); printParam("p1", args[0], out, true); printParam("p2", args[1], out); @@ -55,4 +53,10 @@ public class TwoPositionalParamsDirective extends TestTemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + @Override + public boolean isNestedContentSupported() { + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java index 507b820..220aeef 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java @@ -50,4 +50,10 @@ public class UpperCaseDirective implements TemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return true; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java index 830a16c..318e7ae 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java @@ -189,6 +189,11 @@ public class NumberFormatTest extends TemplateTest { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return false; + } }); assertOutput( "<#assign s1 = n?string>" http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/interpret.txt ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/interpret.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/interpret.txt index fe862e6..0ecb929 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/interpret.txt +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/interpret.txt @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -abcdef -abcdef -abcdef +abcabcabc M \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/interpret.ftl ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/interpret.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/interpret.ftl index 41f8425..f0240e4 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/interpret.ftl +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/interpret.ftl @@ -18,8 +18,9 @@ --> <#global x=["a", "b", "c"]> <#global templateSource = r"<#list x as y>${y}</#list>"> -<@templateSource?interpret>def</@> -<@[templateSource]?interpret>def</@> -<@[templateSource,"id"]?interpret>def</@> +<@templateSource?interpret /> +<@[templateSource]?interpret /> +<@[templateSource,"id"]?interpret /> +<@assertFails message="nested content"><@templateSource?interpret>x</@></@> <#assign t = '<#macro m>M</#macro>'?interpret><@t /><@m/> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java index eb06e23..32f14ca 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java @@ -45,7 +45,8 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; * AST node: {@code <@exp ...>}. * Executes a {@link TemplateCallableModel} that's embeddable directly into the static text (hence "top level"). At * least in the default template language the value must be a {@link TemplateDirectiveModel}, though technically - * calling a {@link TemplateFunctionModel} is possible as well (hence it's not called "dynamic directive call"). + * calling a {@link TemplateFunctionModel} is possible as well (hence this class is not called "dynamic directive + * call"). * <p> * The {@link TemplateCallableModel} object is obtained on runtime by evaluating an expression, and the parameter list * is also validated (how many positional parameters are allowed, what named parameters are supported) then. Hence, the @@ -99,12 +100,14 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { TemplateCallableModel callableValue; TemplateDirectiveModel directive; TemplateFunctionModel function; + boolean nestedContentSupported; { TemplateModel callableValueTM = callableValueExp._eval(env); if (callableValueTM instanceof TemplateDirectiveModel) { callableValue = (TemplateCallableModel) callableValueTM; directive = (TemplateDirectiveModel) callableValueTM; function = null; + nestedContentSupported = directive.isNestedContentSupported(); } else if (callableValueTM instanceof TemplateFunctionModel) { if (!allowCallingFunctions) { // TODO [FM3][CF] Better exception @@ -114,6 +117,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { callableValue = (TemplateCallableModel) callableValueTM; directive = null; function = (TemplateFunctionModel) callableValue; + nestedContentSupported = false; } else if (callableValueTM instanceof ASTDirMacro) { // TODO [FM3][CF] Until macros were refactored to be TemplateDirectiveModel-s, we have this hack here. ASTDirMacro macro = (ASTDirMacro) callableValueTM; @@ -147,6 +151,10 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { } } + if (!nestedContentSupported && hasNestedContent()) { + throw new _MiscTemplateException(env, "Nested content is not supported by this directive."); + } + ArgumentArrayLayout argsLayout = callableValue.getArgumentArrayLayout(); int predefPosArgCnt = argsLayout.getPredefinedPositionalArgumentCount(); int posVarargsArgIdx = argsLayout.getPositionalVarargsArgumentIndex(); @@ -175,7 +183,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { } execArgs[posVarargsArgIdx] = varargsSeq; } else if (positionalArgs != null && positionalArgs.length > predefPosArgCnt) { - throw new _MiscTemplateException(this, + throw new _MiscTemplateException(env, "The target callable ", (predefPosArgCnt != 0 ? new Object[] { "can only have ", predefPosArgCnt } @@ -197,7 +205,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { if (namedVarargsHash == null) { if (namedVarargsArgumentIndex == -1) { Collection<String> validNames = predefNamedArgsMap.getKeys(); - throw new _MiscTemplateException(this, + throw new _MiscTemplateException(env, validNames == null || validNames.isEmpty() ? new Object[] { "The target callable doesn't have any by-name-passed parameters (like ", @@ -225,7 +233,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { } else { TemplateModel result = function.execute(execArgs, env, this); if (result == null) { - throw new _MiscTemplateException(this, "Function has returned no value (or null)"); + throw new _MiscTemplateException(env, "Function has returned no value (or null)"); } // TODO [FM3][CF] throw new BugException("Top-level function call not yet implemented"); @@ -389,7 +397,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { int nestedContentParamNamesSize = nestedContentParamNames != null ? nestedContentParamNames.size() : 0; int nestedContentParamValuesSize = nestedContentParamValues != null ? nestedContentParamValues.length : 0; if (nestedContentParamValuesSize != nestedContentParamNamesSize) { - throw new _MiscTemplateException(this, + throw new _MiscTemplateException(env, "The invocation declares ", (nestedContentParamNamesSize != 0 ? nestedContentParamNamesSize : "no"), " nested content parameter(s)", (nestedContentParamNamesSize != 0 http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java index 4d15516..d9ad1bf 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsMisc.java @@ -200,7 +200,6 @@ class BuiltInsForStringsMisc { @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - // TODO [FM3] Disallow loop vars, and nested content try { boolean lastFIRE = env.setFastInvalidReferenceExceptions(false); try { @@ -222,6 +221,11 @@ class BuiltInsForStringsMisc { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return false; + } } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java index 6995afe..3529c8c 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java @@ -45,4 +45,17 @@ public interface TemplateDirectiveModel extends TemplateCallableModel { void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException; + /** + * Tells if this directive supports having nested content. If {@code false}, yet the caller specifies a non-empty + * (strictly 0-length, not even whitespace is allowed), FreeMarker will throw a {@link TemplateException} with + * descriptive error message, and {@link #execute(TemplateModel[], CallPlace, Writer, Environment)} won't be called. + * If {@code true}, the author of the directive shouldn't forget calling {@link + * CallPlace#executeNestedContent(TemplateModel[], Writer, Environment)}, unless the intent was to skip the nested + * content. (This property was added to prevent the frequent oversight (in FreeMarker 2) where a directive that + * isn't supposed to have nested content doesn't examine if there's a nested content to throw an exception in that + * case. Then if there's nested content, it will be silently skipped during execution, as the directive never + * calls {@link CallPlace#executeNestedContent(TemplateModel[], Writer, Environment)}.) + */ + boolean isNestedContentSupported(); + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/IncludePage.java ---------------------------------------------------------------------- diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/IncludePage.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/IncludePage.java index c6adead..6199fcc 100644 --- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/IncludePage.java +++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/IncludePage.java @@ -189,6 +189,11 @@ public class IncludePage implements TemplateDirectiveModel { return ARGS_LAYOUT; } + @Override + public boolean isNestedContentSupported() { + return false; + } + private static final class CustomParamsRequest extends HttpServletRequestWrapper { private final HashMap paramsMap; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java ---------------------------------------------------------------------- diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java index c51e611..2302f22 100644 --- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java +++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/CustomTagAndELFunctionCombiner.java @@ -113,6 +113,11 @@ class CustomTagAndELFunctionCombiner { public ArgumentArrayLayout getArgumentArrayLayout() { return templateDirectiveModel.getArgumentArrayLayout(); } + + @Override + public boolean isNestedContentSupported() { + return templateDirectiveModel.isNestedContentSupported(); + } } private static class TemplateDirectiveModelAndTemplateMethodModelEx extends CombinedTemplateModel @@ -142,6 +147,11 @@ class CustomTagAndELFunctionCombiner { public ArgumentArrayLayout getArgumentArrayLayout() { return templateDirectiveModel.getArgumentArrayLayout(); } + + @Override + public boolean isNestedContentSupported() { + return templateDirectiveModel.isNestedContentSupported(); + } } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/SimpleTagDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/SimpleTagDirectiveModel.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/SimpleTagDirectiveModel.java index 810a50c..4e7d6c7 100644 --- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/SimpleTagDirectiveModel.java +++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/SimpleTagDirectiveModel.java @@ -111,6 +111,11 @@ class SimpleTagDirectiveModel extends JspTagModelBase implements TemplateDirecti return ARGS_LAYOUT; } + @Override + public boolean isNestedContentSupported() { + return true; + } + static final class TemplateExceptionWrapperJspException extends JspException { public TemplateExceptionWrapperJspException(Throwable cause) { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TagDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TagDirectiveModel.java b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TagDirectiveModel.java index 661046f..86febfa 100644 --- a/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TagDirectiveModel.java +++ b/freemarker-servlet/src/main/java/org/apache/freemarker/servlet/jsp/TagDirectiveModel.java @@ -121,6 +121,11 @@ class TagDirectiveModel extends JspTagModelBase implements TemplateDirectiveMode return ARGS_LAYOUT; } + @Override + public boolean isNestedContentSupported() { + return true; + } + /** * Implements extra methods to help mimicking JSP container behavior around the * {@link TemplateDirectiveModel#execute(TemplateModel[], CallPlace, Writer, Environment)} call. http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java index 0a9e9cd..ffb2c40 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java @@ -70,4 +70,9 @@ public class AssertDirective implements TemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ARGS_LAYOUT; } + + @Override + public boolean isNestedContentSupported() { + return false; + } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java index a02308f..8334c20 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java @@ -80,6 +80,16 @@ public class AssertEqualsDirective implements TemplateDirectiveModel { } } + @Override + public ArgumentArrayLayout getArgumentArrayLayout() { + return ARGS_LAYOUT; + } + + @Override + public boolean isNestedContentSupported() { + return false; + } + private String tryUnwrap(TemplateModel value) throws TemplateModelException { if (value == null) return "null"; // This is the same order as comparison goes: @@ -91,8 +101,4 @@ public class AssertEqualsDirective implements TemplateDirectiveModel { else return value.toString(); } - @Override - public ArgumentArrayLayout getArgumentArrayLayout() { - return ARGS_LAYOUT; - } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java index effc0e7..c089300 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java @@ -135,6 +135,16 @@ public class AssertFailsDirective implements TemplateDirectiveModel { } } + @Override + public ArgumentArrayLayout getArgumentArrayLayout() { + return ARGS_LAYOUT; + } + + @Override + public boolean isNestedContentSupported() { + return true; + } + private String getAsString(TemplateModel value, String paramName, Environment env) throws BadParameterTypeException, TemplateModelException { if (value == null) { @@ -166,8 +176,4 @@ public class AssertFailsDirective implements TemplateDirectiveModel { } } - @Override - public ArgumentArrayLayout getArgumentArrayLayout() { - return ARGS_LAYOUT; - } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/5bd19ade/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/NoOutputDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/NoOutputDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/NoOutputDirective.java index b027974..7e53023 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/NoOutputDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/NoOutputDirective.java @@ -48,4 +48,10 @@ public class NoOutputDirective implements TemplateDirectiveModel { public ArgumentArrayLayout getArgumentArrayLayout() { return ArgumentArrayLayout.PARAMETERLESS; } + + @Override + public boolean isNestedContentSupported() { + return true; + } + }