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 2018/02/28 19:51:04 UTC
[1/6] incubator-freemarker git commit: (JavaDoc improvement)
Repository: incubator-freemarker
Updated Branches:
refs/heads/2.3 0aab5d3ba -> 49ab712c9
(JavaDoc improvement)
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/16ad98c1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/16ad98c1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/16ad98c1
Branch: refs/heads/2.3
Commit: 16ad98c1ed7db20f55582afe9f800104e6fdbb79
Parents: 5065cfe
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 09:49:00 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 09:49:00 2018 +0100
----------------------------------------------------------------------
src/main/java/freemarker/core/Environment.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/16ad98c1/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 310ae9d..47b390a 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -2595,9 +2595,12 @@ public final class Environment extends Configurable {
*
* @param loadedTemplate
* The template to import. Note that it does <em>not</em> need to be a template returned by
- * {@link #getTemplateForImporting(String name)}.
+ * {@link #getTemplateForImporting(String name)}. Not {@code null}.
* @param targetNsVarName
- * The name of the FTL variable that will store the namespace.
+ * The name of the FTL variable that will store the namespace. If {@code null}, the namespace
+ * won't be stored in a variable (but it's still returned).
+ *
+ * @return The namespace of the imported template, already initialized.
*
* @see #getTemplateForImporting(String name)
* @see #importLib(Template includedTemplate, String namespaceVarName)
[6/6] 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/49ab712c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/49ab712c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/49ab712c
Branch: refs/heads/2.3
Commit: 49ab712c9f6e8b3ed47d84e10fa299354c246d19
Parents: 0aab5d3 51c2476
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 20:50:51 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 20:50:51 2018 +0100
----------------------------------------------------------------------
src/main/java/freemarker/core/BuiltIn.java | 12 +-
.../java/freemarker/core/BuiltInsForDates.java | 4 +-
.../core/BuiltInsForExistenceHandling.java | 2 +-
.../core/BuiltInsForMultipleTypes.java | 4 +-
.../freemarker/core/BuiltInsForSequences.java | 6 +-
.../core/BuiltInsForStringsBasic.java | 6 +-
.../freemarker/core/BuiltInsForStringsMisc.java | 8 +-
.../java/freemarker/core/BuiltinVariable.java | 11 +-
src/main/java/freemarker/core/Environment.java | 23 +-
src/main/java/freemarker/core/EvalUtil.java | 8 +-
.../core/GetOptionalTemplateMethod.java | 202 ++++++++++
src/main/java/freemarker/core/Interpret.java | 8 +-
.../java/freemarker/core/IteratorBlock.java | 13 +-
src/main/java/freemarker/core/Macro.java | 2 +-
src/main/java/freemarker/core/MessageUtil.java | 354 ------------------
.../java/freemarker/core/ParseException.java | 2 +-
.../freemarker/core/TemplateClassResolver.java | 4 +-
.../java/freemarker/core/TemplateObject.java | 4 +-
.../java/freemarker/core/TransformBlock.java | 2 +-
src/main/java/freemarker/core/UnifiedCall.java | 4 +-
...nDateTypeFormattingUnsupportedException.java | 2 +-
...nownDateTypeParsingUnsupportedException.java | 2 +-
.../java/freemarker/core/_DelayedAOrAn.java | 2 +-
src/main/java/freemarker/core/_MessageUtil.java | 371 +++++++++++++++++++
.../template/utility/TemplateModelUtils.java | 90 +++++
src/main/javacc/FTL.jj | 2 +-
src/manual/en_US/book.xml | 158 +++++++-
.../core/GetOptionalTemplateTest.java | 179 +++++++++
.../template/utility/TemplateModelUtilTest.java | 160 ++++++++
29 files changed, 1225 insertions(+), 420 deletions(-)
----------------------------------------------------------------------
[3/6] incubator-freemarker git commit: Fixed build error (and some
more) in: Made some freemarker.core.MessageUtil method public (so now other
freemarker packages can use it)
Posted by dd...@apache.org.
Fixed build error (and some more) in: Made some freemarker.core.MessageUtil method public (so now other freemarker packages can use it)
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/c533df56
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/c533df56
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/c533df56
Branch: refs/heads/2.3
Commit: c533df561cc788e2cf46f03f6f402d351dc730cb
Parents: d7c654d
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 10:00:13 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 10:02:37 2018 +0100
----------------------------------------------------------------------
src/main/java/freemarker/core/_MessageUtil.java | 52 +++++++++++++-------
src/main/javacc/FTL.jj | 2 +-
2 files changed, 35 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c533df56/src/main/java/freemarker/core/_MessageUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/_MessageUtil.java b/src/main/java/freemarker/core/_MessageUtil.java
index a84eb9d..db097db 100644
--- a/src/main/java/freemarker/core/_MessageUtil.java
+++ b/src/main/java/freemarker/core/_MessageUtil.java
@@ -23,6 +23,8 @@ import java.util.ArrayList;
import freemarker.template.Template;
import freemarker.template.TemplateException;
+import freemarker.template.TemplateHashModelEx;
+import freemarker.template.TemplateHashModelEx2;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.utility.StringUtil;
@@ -128,7 +130,7 @@ public class _MessageUtil {
* If will truncate the string at line-breaks too.
* The truncation is always signaled with a a {@code "..."} at the end of the result string.
*/
- static String shorten(String s, int maxLength) {
+ public static String shorten(String s, int maxLength) {
if (maxLength < 5) maxLength = 5;
boolean isTruncated = false;
@@ -168,7 +170,7 @@ public class _MessageUtil {
}
}
- static StringBuilder appendExpressionAsUntearable(StringBuilder sb, Expression argExp) {
+ public static StringBuilder appendExpressionAsUntearable(StringBuilder sb, Expression argExp) {
boolean needParen =
!(argExp instanceof NumberLiteral)
&& !(argExp instanceof StringLiteral)
@@ -188,11 +190,11 @@ public class _MessageUtil {
return sb;
}
- static TemplateModelException newArgCntError(String methodName, int argCnt, int expectedCnt) {
+ public static TemplateModelException newArgCntError(String methodName, int argCnt, int expectedCnt) {
return newArgCntError(methodName, argCnt, expectedCnt, expectedCnt);
}
- static TemplateModelException newArgCntError(String methodName, int argCnt, int minCnt, int maxCnt) {
+ public static TemplateModelException newArgCntError(String methodName, int argCnt, int minCnt, int maxCnt) {
ArrayList/*<Object>*/ desc = new ArrayList(20);
desc.add(methodName);
@@ -234,34 +236,34 @@ public class _MessageUtil {
return new _TemplateModelException(desc.toArray());
}
- static TemplateModelException newMethodArgMustBeStringException(String methodName, int argIdx, TemplateModel arg) {
+ public static TemplateModelException newMethodArgMustBeStringException(String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "string", arg);
}
- static TemplateModelException newMethodArgMustBeNumberException(String methodName, int argIdx, TemplateModel arg) {
+ public static TemplateModelException newMethodArgMustBeNumberException(String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "number", arg);
}
- static TemplateModelException newMethodArgMustBeBooleanException(String methodName, int argIdx, TemplateModel arg) {
+ public static TemplateModelException newMethodArgMustBeBooleanException(String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "boolean", arg);
}
- static TemplateModelException newMethodArgMustBeExtendedHashException(
+ public static TemplateModelException newMethodArgMustBeExtendedHashException(
String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "extended hash", arg);
}
- static TemplateModelException newMethodArgMustBeSequenceException(
+ public static TemplateModelException newMethodArgMustBeSequenceException(
String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence", arg);
}
- static TemplateModelException newMethodArgMustBeSequenceOrCollectionException(
+ public static TemplateModelException newMethodArgMustBeSequenceOrCollectionException(
String methodName, int argIdx, TemplateModel arg) {
return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence or collection", arg);
}
- static TemplateModelException newMethodArgUnexpectedTypeException(
+ public static TemplateModelException newMethodArgUnexpectedTypeException(
String methodName, int argIdx, String expectedType, TemplateModel arg) {
return new _TemplateModelException(
methodName, "(...) expects ", new _DelayedAOrAn(expectedType), " as argument #", Integer.valueOf(argIdx + 1),
@@ -271,7 +273,7 @@ public class _MessageUtil {
/**
* The type of the argument was good, but it's value wasn't.
*/
- static TemplateModelException newMethodArgInvalidValueException(
+ public static TemplateModelException newMethodArgInvalidValueException(
String methodName, int argIdx, Object... details) {
return new _TemplateModelException(
methodName, "(...) argument #", Integer.valueOf(argIdx + 1),
@@ -281,17 +283,17 @@ public class _MessageUtil {
/**
* The type of the argument was good, but the values of two or more arguments are inconsistent with each other.
*/
- static TemplateModelException newMethodArgsInvalidValueException(
+ public static TemplateModelException newMethodArgsInvalidValueException(
String methodName, Object... details) {
return new _TemplateModelException(methodName, "(...) arguments have invalid value: ", details);
}
- static TemplateException newInstantiatingClassNotAllowedException(String className, Environment env) {
+ public static TemplateException newInstantiatingClassNotAllowedException(String className, Environment env) {
return new _MiscTemplateException(env,
"Instantiating ", className, " is not allowed in the template for security reasons.");
}
- static _TemplateModelException newCantFormatUnknownTypeDateException(
+ public static _TemplateModelException newCantFormatUnknownTypeDateException(
Expression dateSourceExpr, UnknownDateTypeFormattingUnsupportedException cause) {
return new _TemplateModelException(cause, null, new _ErrorDescriptionBuilder(
_MessageUtil.UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE)
@@ -299,7 +301,7 @@ public class _MessageUtil {
.tips(_MessageUtil.UNKNOWN_DATE_TO_STRING_TIPS));
}
- static TemplateException newCantFormatDateException(TemplateDateFormat format, Expression dataSrcExp,
+ public static TemplateException newCantFormatDateException(TemplateDateFormat format, Expression dataSrcExp,
TemplateValueFormatException e, boolean useTempModelExc) {
_ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
"Failed to format date/time/datetime with format ", new _DelayedJQuote(format.getDescription()), ": ",
@@ -310,7 +312,7 @@ public class _MessageUtil {
: new _MiscTemplateException(e, (Environment) null, desc);
}
- static TemplateException newCantFormatNumberException(TemplateNumberFormat format, Expression dataSrcExp,
+ public static TemplateException newCantFormatNumberException(TemplateNumberFormat format, Expression dataSrcExp,
TemplateValueFormatException e, boolean useTempModelExc) {
_ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
"Failed to format number with format ", new _DelayedJQuote(format.getDescription()), ": ",
@@ -321,10 +323,24 @@ public class _MessageUtil {
: new _MiscTemplateException(e, (Environment) null, desc);
}
+ public static _ErrorDescriptionBuilder traditionalHashExKeyMustBeStringExceptionMessage(
+ TemplateModel key, TemplateHashModelEx listedHashEx) {
+ return new _ErrorDescriptionBuilder(
+ "When listing key-value pairs of traditional hash "
+ + "implementations, all keys must be strings, but one of them "
+ + "was ",
+ new _DelayedAOrAn(new _DelayedFTLTypeDescription(key)), "."
+ ).tip("The listed value's TemplateModel class was ",
+ new _DelayedShortClassName(listedHashEx.getClass()),
+ ", which doesn't implement ",
+ new _DelayedShortClassName(TemplateHashModelEx2.class),
+ ", which leads to this restriction.");
+ }
+
/**
* @return "a" or "an" or "a(n)" (or "" for empty string) for an FTL type name
*/
- static String getAOrAn(String s) {
+ static public String getAOrAn(String s) {
if (s == null) return null;
if (s.length() == 0) return "";
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c533df56/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 111ec89..3e87032 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -716,7 +716,7 @@ TOKEN_MGR_DECLS:
))
+ (namingConventionEstabilisher != null
? "estabilished by auto-detection at "
- + MessageUtil.formatPosition(
+ + _MessageUtil.formatPosition(
namingConventionEstabilisher.beginLine, namingConventionEstabilisher.beginColumn)
+ " by token " + StringUtil.jQuote(namingConventionEstabilisher.image.trim())
: "")
[5/6] incubator-freemarker git commit: FREEMARKER-84: Added
.get_optional_template
Posted by dd...@apache.org.
FREEMARKER-84: Added .get_optional_template
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/51c24766
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/51c24766
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/51c24766
Branch: refs/heads/2.3
Commit: 51c2476621809d8f4183f23e894be0106cabe810
Parents: 59f2e7b
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 20:49:36 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 20:49:36 2018 +0100
----------------------------------------------------------------------
.../java/freemarker/core/BuiltinVariable.java | 11 +-
.../core/GetOptionalTemplateMethod.java | 202 +++++++++++++++++++
src/manual/en_US/book.xml | 146 +++++++++++++-
.../core/GetOptionalTemplateTest.java | 179 ++++++++++++++++
.../template/utility/TemplateModelUtilTest.java | 35 ++--
5 files changed, 556 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51c24766/src/main/java/freemarker/core/BuiltinVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltinVariable.java b/src/main/java/freemarker/core/BuiltinVariable.java
index 41286dd..1b7617c 100644
--- a/src/main/java/freemarker/core/BuiltinVariable.java
+++ b/src/main/java/freemarker/core/BuiltinVariable.java
@@ -72,7 +72,8 @@ final class BuiltinVariable extends Expression {
static final String URL_ESCAPING_CHARSET_CC = "urlEscapingCharset";
static final String URL_ESCAPING_CHARSET = "url_escaping_charset";
static final String NOW = "now";
-
+ static final String GET_OPTIONAL_TEMPLATE = "get_optional_template";
+ static final String GET_OPTIONAL_TEMPLATE_CC = "getOptionalTemplate";
static final String[] SPEC_VAR_NAMES = new String[] {
AUTO_ESC_CC,
AUTO_ESC,
@@ -83,6 +84,8 @@ final class BuiltinVariable extends Expression {
DATA_MODEL_CC,
DATA_MODEL,
ERROR,
+ GET_OPTIONAL_TEMPLATE_CC,
+ GET_OPTIONAL_TEMPLATE,
GLOBALS,
INCOMPATIBLE_IMPROVEMENTS_CC,
INCOMPATIBLE_IMPROVEMENTS,
@@ -239,6 +242,12 @@ final class BuiltinVariable extends Expression {
if (name == INCOMPATIBLE_IMPROVEMENTS || name == INCOMPATIBLE_IMPROVEMENTS_CC) {
return new SimpleScalar(env.getConfiguration().getIncompatibleImprovements().toString());
}
+ if (name == GET_OPTIONAL_TEMPLATE) {
+ return GetOptionalTemplateMethod.INSTANCE;
+ }
+ if (name == GET_OPTIONAL_TEMPLATE_CC) {
+ return GetOptionalTemplateMethod.INSTANCE_CC;
+ }
throw new _MiscTemplateException(this,
"Invalid special variable: ", name);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51c24766/src/main/java/freemarker/core/GetOptionalTemplateMethod.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/GetOptionalTemplateMethod.java b/src/main/java/freemarker/core/GetOptionalTemplateMethod.java
new file mode 100644
index 0000000..090341b
--- /dev/null
+++ b/src/main/java/freemarker/core/GetOptionalTemplateMethod.java
@@ -0,0 +1,202 @@
+/*
+ * 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.core;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import freemarker.template.MalformedTemplateNameException;
+import freemarker.template.SimpleHash;
+import freemarker.template.Template;
+import freemarker.template.TemplateBooleanModel;
+import freemarker.template.TemplateDirectiveBody;
+import freemarker.template.TemplateDirectiveModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateHashModelEx;
+import freemarker.template.TemplateHashModelEx2.KeyValuePair;
+import freemarker.template.TemplateHashModelEx2.KeyValuePairIterator;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateScalarModel;
+import freemarker.template.utility.TemplateModelUtils;
+
+/**
+ * Implements {@code .get_optional_template(name, options)}.
+ */
+class GetOptionalTemplateMethod implements TemplateMethodModelEx {
+
+ static final GetOptionalTemplateMethod INSTANCE = new GetOptionalTemplateMethod(
+ BuiltinVariable.GET_OPTIONAL_TEMPLATE);
+ static final GetOptionalTemplateMethod INSTANCE_CC = new GetOptionalTemplateMethod(
+ BuiltinVariable.GET_OPTIONAL_TEMPLATE_CC);
+
+ private static final String OPTION_ENCODING = "encoding";
+ private static final String OPTION_PARSE = "parse";
+
+ private static final String RESULT_INCLUDE = "include";
+ private static final String RESULT_IMPORT = "import";
+ private static final String RESULT_EXISTS = "exists";
+
+ /** Used in error messages */
+ private final String methodName;
+
+ private GetOptionalTemplateMethod(String builtInVarName) {
+ this.methodName = "." + builtInVarName;
+ }
+
+ public Object exec(List args) throws TemplateModelException {
+ final int argCnt = args.size();
+ if (argCnt < 1 || argCnt > 2) {
+ throw _MessageUtil.newArgCntError(methodName, argCnt, 1, 2);
+ }
+
+ final Environment env = Environment.getCurrentEnvironment();
+ if (env == null) {
+ throw new IllegalStateException("No freemarer.core.Environment is associated to the current thread.");
+ }
+
+ final String absTemplateName;
+ {
+ TemplateModel arg = (TemplateModel) args.get(0);
+ if (!(arg instanceof TemplateScalarModel)) {
+ throw _MessageUtil.newMethodArgMustBeStringException(methodName, 0, arg);
+ }
+ String templateName = EvalUtil.modelToString((TemplateScalarModel) arg, null, env);
+
+ try {
+ absTemplateName = env.toFullTemplateName(env.getCurrentTemplate().getName(), templateName);
+ } catch (MalformedTemplateNameException e) {
+ throw new _TemplateModelException(
+ e, "Failed to convert template path to full path; see cause exception.");
+ }
+ }
+
+ final TemplateHashModelEx options;
+ if (argCnt > 1) {
+ TemplateModel arg = (TemplateModel) args.get(1);
+ if (!(arg instanceof TemplateHashModelEx)) {
+ throw _MessageUtil.newMethodArgMustBeExtendedHashException(methodName, 1, arg);
+ }
+ options = (TemplateHashModelEx) arg;
+ } else {
+ options = null;
+ }
+
+ String encoding = null;
+ boolean parse = true;
+ if (options != null) {
+ final KeyValuePairIterator kvpi = TemplateModelUtils.getKeyValuePairIterator(options);
+ while (kvpi.hasNext()) {
+ final KeyValuePair kvp = kvpi.next();
+
+ final String optName;
+ {
+ TemplateModel optNameTM = kvp.getKey();
+ if (!(optNameTM instanceof TemplateScalarModel)) {
+ throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
+ "All keys in the options hash must be strings, but found ",
+ new _DelayedAOrAn(new _DelayedFTLTypeDescription(optNameTM)));
+ }
+ optName = ((TemplateScalarModel) optNameTM).getAsString();
+ }
+
+ final TemplateModel optValue = kvp.getValue();
+
+ if (OPTION_ENCODING.equals(optName)) {
+ encoding = getStringOption(OPTION_ENCODING, optValue);
+ } else if (OPTION_PARSE.equals(optName)) {
+ parse = getBooleanOption(OPTION_PARSE, optValue);
+ } else {
+ throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
+ "Unsupported option ", new _DelayedJQuote(optName), "; valid names are: ",
+ new _DelayedJQuote(OPTION_ENCODING), ", ", new _DelayedJQuote(OPTION_PARSE), ".");
+ }
+ }
+ }
+
+ final Template template;
+ try {
+ template = env.getTemplateForInclusion(absTemplateName, encoding, parse, true);
+ } catch (IOException e) {
+ throw new _TemplateModelException(
+ "Error when trying to include template ", new _DelayedJQuote(absTemplateName));
+ }
+
+ SimpleHash result = new SimpleHash(env.getObjectWrapper());
+ result.put(RESULT_EXISTS, template != null);
+ // If the template is missing, result.include and such will be missing to, so that a default can be
+ // conveniently provided like in <@optTemp.include!myDefaultMacro />.
+ if (template != null) {
+ result.put(RESULT_INCLUDE, new TemplateDirectiveModel() {
+ public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+ throws TemplateException, IOException {
+ if (!params.isEmpty()) {
+ throw new TemplateException("This directive supports no parameters.", env);
+ }
+ if (loopVars.length != 0) {
+ throw new TemplateException("This directive supports no loop variables.", env);
+ }
+ if (body != null) {
+ throw new TemplateException("This directive supports no nested conetnt.", env);
+ }
+
+ env.include(template);
+ }
+ });
+ result.put(RESULT_IMPORT, new TemplateMethodModelEx() {
+ public Object exec(List args) throws TemplateModelException {
+ if (!args.isEmpty()) {
+ throw new TemplateModelException("This method supports no parameters.");
+ }
+
+ try {
+ return env.importLib(template, null);
+ } catch (IOException e) {
+ throw new _TemplateModelException(e, "Failed to import loaded template; see cause exception");
+ } catch (TemplateException e) {
+ throw new _TemplateModelException(e, "Failed to import loaded template; see cause exception");
+ }
+ }
+ });
+ }
+ return result;
+ }
+
+ private boolean getBooleanOption(String optionName, TemplateModel value) throws TemplateModelException {
+ if (!(value instanceof TemplateBooleanModel)) {
+ throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
+ "The value of the ", new _DelayedJQuote(optionName), " option must be a boolean, but it was ",
+ new _DelayedAOrAn(new _DelayedFTLTypeDescription(value)), ".");
+ }
+ return ((TemplateBooleanModel) value).getAsBoolean();
+ }
+
+ private String getStringOption(String optionName, TemplateModel value) throws TemplateModelException {
+ if (!(value instanceof TemplateScalarModel)) {
+ throw _MessageUtil.newMethodArgInvalidValueException(methodName, 1,
+ "The value of the ", new _DelayedJQuote(optionName), " option must be a string, but it was ",
+ new _DelayedAOrAn(new _DelayedFTLTypeDescription(value)), ".");
+ }
+ return EvalUtil.modelToString((TemplateScalarModel) value, null, null);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51c24766/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 56851f3..7fa85fa 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -23378,6 +23378,14 @@ There was no specific handler for node y
</listitem>
<listitem>
+ <para><literal>get_optional_template</literal>: This is a method
+ that's used when you need to include or import a template that's
+ possibly missing, and you need to handle that case on some special
+ way. <link linkend="ref_specvar_get_optional_template">More
+ details...</link></para>
+ </listitem>
+
+ <listitem>
<para><literal>pass</literal>: This is a macro that does nothing. It
has no parameters. Mostly used as no-op node handler in XML
processing.</para>
@@ -23432,7 +23440,9 @@ There was no specific handler for node y
</listitem>
<listitem>
- <para><literal>vars</literal>: Expression
+ <para><indexterm>
+ <primary>vars</primary>
+ </indexterm><literal>vars</literal>: Expression
<literal>.vars.foo</literal> returns the same variable as expression
<literal>foo</literal>. It's useful if for some reasons you have to
use square bracket syntax, since that works only for hash sub
@@ -23459,6 +23469,140 @@ There was no specific handler for node y
2.3.21-nightly_20140726T151800Z.</para>
</listitem>
</itemizedlist>
+
+ <simplesect xml:id="ref_specvar_get_optional_template">
+ <title>Using get_optional_template</title>
+
+ <indexterm>
+ <primary>get_optional_template</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>include optional</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>import optional</primary>
+ </indexterm>
+
+ <para>This special variable is used when you need to include or import
+ a template that's possibly missing, and you need to handle that case
+ on some special way. It a method (so you meant to call it) that has
+ the following parameters:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>The name of the template (can be relative or absolute), like
+ <literal>"/commonds/footer.ftl"</literal>; similar to the first
+ parameter of the <link
+ linkend="ref.directive.include"><literal>include</literal>
+ directive</link>. Required, string.</para>
+ </listitem>
+
+ <listitem>
+ <para>An optional hash of options, like <literal>{ 'parse': false,
+ 'encoding': 'UTF-16BE' }</literal>. The valid keys are
+ <literal>encoding</literal> and <literal>parse</literal>. The
+ meaning of these are the same as of the similarly named <link
+ linkend="ref.directive.include"><literal>include</literal>
+ directive</link> parameters.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>This method returns a hash that contains the following
+ entries:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>exists</literal>: A boolean that tells if the
+ template was found.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>include</literal>: A directive that, when called,
+ includes the template. Calling this directive is similar to
+ calling the <link
+ linkend="ref.directive.include"><literal>include</literal>
+ directive</link>, but of course with this you spare looking up the
+ template again. This directive has no parameters, nor nested
+ content. If <literal>exists</literal> is <literal>false</literal>,
+ this key will be missing; see later how can this be utilized with
+ <link linkend="dgui_template_exp_missing_default">the
+ <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal>
+ operator</link>.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>import</literal>: A method that, when called,
+ imports the template, and returns the namespace of the imported
+ template. Calling this method is similar to calling the
+ <literal>import</literal> directive, but of course with this you
+ spare looking up the template again, also, it doesn't assign the
+ namespace to anything, just returns it. The method has no
+ parameters. If <literal>exists</literal> is
+ <literal>false</literal>, this key will be missing; see later how
+ can this be utilized with <link
+ linkend="dgui_template_exp_missing_default">the
+ <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal>
+ operator</link>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When this method is called (like
+ <literal>.get_optional_template('some.ftl')</literal>), it immediately
+ loads the template if it exists, but doesn't yet process it, so it
+ doesn't have any visible effect yet. The template will be processed
+ only when <literal>include</literal> or <literal>import</literal>
+ members of the returned structure is called. (Of course, when we say
+ that it loads the template, it actually looks it up in the template
+ cache, just like the <link
+ linkend="ref.directive.include"><literal>include</literal>
+ directive</link> does.)</para>
+
+ <para>While it's not an error if the template is missing, it's an
+ error if it does exist but still can't be loaded due to syntactical
+ errors in it, or due to some I/O error.</para>
+
+ <para>Example, in which depending on if <literal>some.ftl</literal>
+ exists, we either print <quote>Template was found:</quote> and the
+ include the template as <literal><#include 'some.ftl'></literal>
+ would, otherwise it we print <quote>Template was
+ missing.</quote>:</para>
+
+ <programlisting role="template"><#assign optTemp = .get_optional_template('some.ftl')>
+<#if optTemp.exists>
+ Template was found:
+ <@optTemp.include />
+<#else>
+ Template was missing.
+</#if></programlisting>
+
+ <para>Example, in which we try to include <literal>some.ftl</literal>,
+ but if that's missing then we try to include
+ <literal>some-fallback.ftl</literal>, and if that's missing too then
+ we call the <literal>ultimateFallback</literal> macro instead of
+ including anything (note the <literal>!</literal>-s after the
+ <literal>include</literal>-s; they belong to <link
+ linkend="dgui_template_exp_missing_default">the
+ <literal><replaceable>exp</replaceable>!<replaceable>default</replaceable></literal>
+ operator</link>):</para>
+
+ <programlisting role="template"><#macro ultimateFallback>
+ Something
+</#macro>
+
+<@(
+ .get_optional_template('some.ftl').include!
+ .get_optional_template('some-fallback.ftl').include!
+ ultimateFallback
+) /></programlisting>
+
+ <para>Example, which behaves like <literal><#import 'tags.ftl' as
+ tags></literal>, except that if <literal>tags.ftl</literal> is
+ missing, then it creates an empty <literal>tags</literal> hash:</para>
+
+ <programlisting role="template"><#assign tags = (.get_optional_template('tags.ftl').import())!{}></programlisting>
+ </simplesect>
</chapter>
<chapter xml:id="ref_reservednames">
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51c24766/src/test/java/freemarker/core/GetOptionalTemplateTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/GetOptionalTemplateTest.java b/src/test/java/freemarker/core/GetOptionalTemplateTest.java
new file mode 100644
index 0000000..4ceb3e4
--- /dev/null
+++ b/src/test/java/freemarker/core/GetOptionalTemplateTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.core;
+
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Test;
+
+import freemarker.cache.ByteArrayTemplateLoader;
+import freemarker.cache.MultiTemplateLoader;
+import freemarker.cache.StringTemplateLoader;
+import freemarker.cache.TemplateLoader;
+import freemarker.template.Configuration;
+import freemarker.test.TemplateTest;
+
+public class GetOptionalTemplateTest extends TemplateTest {
+
+ private ByteArrayTemplateLoader byteArrayTemplateLoader = new ByteArrayTemplateLoader();
+
+ @Override
+ protected Configuration createConfiguration() throws Exception {
+ Configuration cfg = super.createConfiguration();
+ cfg.setTemplateLoader(
+ new MultiTemplateLoader(new TemplateLoader[] {
+ new StringTemplateLoader(), byteArrayTemplateLoader
+ }));
+ return cfg;
+ }
+
+ @Test
+ public void testBasicsWhenTemplateExists() throws Exception {
+ addTemplate("inc.ftl", "<#assign x = (x!0) + 1>inc ${x}");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc.ftl')>"
+ + "Exists: ${t.exists?c}; "
+ + "Include: <@t.include />, <@t.include />; "
+ + "Import: <#assign ns1 = t.import()><#assign ns2 = t.import()>${ns1.x}, ${ns2.x}; "
+ + "Aliased: <#assign x = 9 in ns1>${ns1.x}, ${ns2.x}, <#import 'inc.ftl' as ns3>${ns3.x}",
+ "Exists: true; "
+ + "Include: inc 1, inc 2; "
+ + "Import: 1, 1; "
+ + "Aliased: 9, 9, 9"
+ );
+ }
+
+ @Test
+ public void testBasicsWhenTemplateIsMissing() throws Exception {
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('missing.ftl')>"
+ + "Exists: ${t.exists?c}; "
+ + "Include: ${t.include???c}; "
+ + "Import: ${t.import???c}",
+ "Exists: false; "
+ + "Include: false; "
+ + "Import: false"
+ );
+ }
+
+ @Test
+ public void testOptions() throws Exception {
+ addTemplate("inc.ftl", "${1}");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc.ftl', { 'parse': false })>"
+ + "<@t.include />",
+ "${1}");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc.ftl')>"
+ + "<@t.include />",
+ "1");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc.ftl', {})>"
+ + "<@t.include />",
+ "1");
+
+ byteArrayTemplateLoader.putTemplate("inc-u16.ftl", "foo".getBytes(StandardCharsets.UTF_16BE));
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc-u16.ftl', { 'encoding': 'utf-16be' })>"
+ + "<@t.include />",
+ "foo");
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc-u16.ftl')>"
+ + "<@t.include />",
+ "\u0000f\u0000o\u0000o");
+
+ byteArrayTemplateLoader.putTemplate("inc-u16.ftl", "foo${1}".getBytes(StandardCharsets.UTF_16BE));
+ assertOutput(""
+ + "<#assign t = .getOptionalTemplate('inc-u16.ftl', { 'parse': false, 'encoding': 'utf-16be' })>"
+ + "<@t.include />",
+ "foo${1}");
+ }
+
+ @Test
+ public void testRelativeAndAbsolutePath() throws Exception {
+ addTemplate("lib/inc.ftl", "included");
+
+ addTemplate("test1.ftl", "<#include 'lib/inc.ftl'>");
+ assertOutputForNamed("test1.ftl", "included");
+
+ addTemplate("lib/test2.ftl", "<#include '/lib/inc.ftl'>");
+ assertOutputForNamed("lib/test2.ftl", "included");
+
+ addTemplate("lib/test3.ftl", "<#include 'inc.ftl'>");
+ assertOutputForNamed("lib/test3.ftl", "included");
+
+ addTemplate("sub/test4.ftl", "<#include '../lib/inc.ftl'>");
+ assertOutputForNamed("sub/test4.ftl", "included");
+ }
+
+ @Test
+ public void testUseCase1() throws Exception {
+ addTemplate("lib/inc.ftl", "included");
+ assertOutput(""
+ + "<#macro test templateName>"
+ + "<#local t = .getOptionalTemplate(templateName)>"
+ + "<#if t.exists>"
+ + "before <@t.include /> after"
+ + "<#else>"
+ + "missing"
+ + "</#if>"
+ + "</#macro>"
+ + "<@test 'lib/inc.ftl' />; "
+ + "<@test 'inc.ftl' />",
+ "before included after; missing");
+ }
+
+ @Test
+ public void testUseCase2() throws Exception {
+ addTemplate("found.ftl", "found");
+ assertOutput(""
+ + "<@("
+ + ".getOptionalTemplate('missing1.ftl').include!"
+ + ".getOptionalTemplate('missing2.ftl').include!"
+ + ".getOptionalTemplate('found.ftl').include!"
+ + ".getOptionalTemplate('missing3.ftl').include"
+ + ") />",
+ "found");
+ assertOutput(""
+ + "<#macro fallback>fallback</#macro>"
+ + "<@("
+ + ".getOptionalTemplate('missing1.ftl').include!"
+ + ".getOptionalTemplate('missing2.ftl').include!"
+ + "fallback"
+ + ") />",
+ "fallback");
+ }
+
+ @Test
+ public void testWrongArguments() throws Exception {
+ assertErrorContains("<#assign t = .getOptionalTemplate()>", ".getOptionalTemplate", "arguments", "none");
+ assertErrorContains("<#assign t = .get_optional_template()>", ".get_optional_template", "arguments", "none");
+ assertErrorContains("<#assign t = .getOptionalTemplate(1, 2, 3)>", "arguments", "3");
+ assertErrorContains("<#assign t = .getOptionalTemplate(1)>", "#1", "string", "number");
+ assertErrorContains("<#assign t = .getOptionalTemplate('x', 1)>", "#2", "hash", "number");
+ assertErrorContains("<#assign t = .getOptionalTemplate('x', { 'foo': 1 })>",
+ "#2", "foo", "encoding", "parse");
+ assertErrorContains("<#assign t = .getOptionalTemplate('x', { 'parse': 1 })>",
+ "#2", "parse", "number", "boolean");
+ assertErrorContains("<#assign t = .getOptionalTemplate('x', { 'encoding': 1 })>",
+ "#2", "encoding", "number", "string");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/51c24766/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java b/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
index 6179e17..c93a2e5 100644
--- a/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
+++ b/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
@@ -33,35 +33,35 @@ import freemarker.template.DefaultNonListCollectionAdapter;
import freemarker.template.DefaultObjectWrapperBuilder;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModelEx;
+import freemarker.template.TemplateHashModelEx2;
import freemarker.template.TemplateHashModelEx2.KeyValuePair;
import freemarker.template.TemplateHashModelEx2.KeyValuePairIterator;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateNumberModel;
import freemarker.template.TemplateScalarModel;
-import freemarker.test.TemplateTest;
-public class TemplateModelUtilTest extends TemplateTest {
+public class TemplateModelUtilTest {
@Test
public void testGetKeyValuePairIterator() throws Exception {
Map<Object, Object> map = new LinkedHashMap<Object, Object>();
TemplateHashModelEx thme = new TemplateHashModelExOnly(map);
- assertetKeyValuePairIteratorResult("", thme);
+ assertetGetKeyValuePairIteratorContent("", thme);
map.put("k1", 11);
- assertetKeyValuePairIteratorResult("str(k1): num(11)", thme);
+ assertetGetKeyValuePairIteratorContent("str(k1): num(11)", thme);
map.put("k2", "v2");
- assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): str(v2)", thme);
+ assertetGetKeyValuePairIteratorContent("str(k1): num(11), str(k2): str(v2)", thme);
map.put("k2", null);
- assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): null", thme);
+ assertetGetKeyValuePairIteratorContent("str(k1): num(11), str(k2): null", thme);
map.put(3, 33);
try {
- assertetKeyValuePairIteratorResult("fails anyway...", thme);
+ assertetGetKeyValuePairIteratorContent("fails anyway...", thme);
fail();
} catch (TemplateModelException e) {
assertThat(e.getMessage(),
@@ -71,7 +71,7 @@ public class TemplateModelUtilTest extends TemplateTest {
map.put(null, 44);
try {
- assertetKeyValuePairIteratorResult("fails anyway...", thme);
+ assertetGetKeyValuePairIteratorContent("fails anyway...", thme);
fail();
} catch (TemplateModelException e) {
assertThat(e.getMessage(),
@@ -83,19 +83,20 @@ public class TemplateModelUtilTest extends TemplateTest {
public void testGetKeyValuePairIteratorWithEx2() throws Exception {
Map<Object, Object> map = new LinkedHashMap<Object, Object>();
TemplateHashModelEx thme = DefaultMapAdapter.adapt(
- map, (ObjectWrapperWithAPISupport) getConfiguration().getObjectWrapper());
+ map, new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27).build());
- assertetKeyValuePairIteratorResult("", thme);
+ assertetGetKeyValuePairIteratorContent("", thme);
map.put("k1", 11);
map.put("k2", "v2");
map.put("k2", null);
map.put(3, 33);
map.put(null, 44);
- assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): null, num(3): num(33), null: num(44)", thme);
+ assertetGetKeyValuePairIteratorContent(
+ "str(k1): num(11), str(k2): null, num(3): num(33), null: num(44)", thme);
}
- private void assertetKeyValuePairIteratorResult(String expected, TemplateHashModelEx thme)
+ private void assertetGetKeyValuePairIteratorContent(String expected, TemplateHashModelEx thme)
throws TemplateModelException {
StringBuilder sb = new StringBuilder();
KeyValuePairIterator kvpi = TemplateModelUtils.getKeyValuePairIterator(thme);
@@ -104,11 +105,12 @@ public class TemplateModelUtilTest extends TemplateTest {
if (sb.length() != 0) {
sb.append(", ");
}
- sb.append(toAssertionString(kvp.getKey())).append(": ").append(toAssertionString(kvp.getValue()));
+ sb.append(toValueAssertionString(kvp.getKey())).append(": ")
+ .append(toValueAssertionString(kvp.getValue()));
}
}
- private String toAssertionString(TemplateModel model) throws TemplateModelException {
+ private String toValueAssertionString(TemplateModel model) throws TemplateModelException {
if (model instanceof TemplateNumberModel) {
return "num(" + ((TemplateNumberModel) model).getAsNumber() + ")";
} else if (model instanceof TemplateScalarModel) {
@@ -120,6 +122,9 @@ public class TemplateModelUtilTest extends TemplateTest {
throw new IllegalArgumentException("Type unsupported by test: " + model.getClass().getName());
}
+ /**
+ * Deliberately doesn't implement {@link TemplateHashModelEx2}, only {@link TemplateHashModelEx}.
+ */
private static class TemplateHashModelExOnly implements TemplateHashModelEx {
private final Map<?, ?> map;
@@ -139,7 +144,7 @@ public class TemplateModelUtilTest extends TemplateTest {
}
public int size() throws TemplateModelException {
- return 2;
+ return map.size();
}
public TemplateCollectionModel keys() throws TemplateModelException {
[2/6] incubator-freemarker git commit: Made
freemarker.core.MessageUtil public but unpublished (so now other freemarker
packages can use it)
Posted by dd...@apache.org.
Made freemarker.core.MessageUtil public but unpublished (so now other freemarker packages can use it)
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/d7c654db
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/d7c654db
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/d7c654db
Branch: refs/heads/2.3
Commit: d7c654db6cb4c535f51eb22d63200e376f0b4bca
Parents: 16ad98c
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 09:54:05 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 09:54:05 2018 +0100
----------------------------------------------------------------------
src/main/java/freemarker/core/BuiltIn.java | 12 +-
.../java/freemarker/core/BuiltInsForDates.java | 4 +-
.../core/BuiltInsForExistenceHandling.java | 2 +-
.../core/BuiltInsForMultipleTypes.java | 4 +-
.../freemarker/core/BuiltInsForSequences.java | 6 +-
.../core/BuiltInsForStringsBasic.java | 6 +-
.../freemarker/core/BuiltInsForStringsMisc.java | 8 +-
src/main/java/freemarker/core/Environment.java | 16 +-
src/main/java/freemarker/core/EvalUtil.java | 8 +-
src/main/java/freemarker/core/Interpret.java | 8 +-
src/main/java/freemarker/core/Macro.java | 2 +-
src/main/java/freemarker/core/MessageUtil.java | 354 ------------------
.../java/freemarker/core/ParseException.java | 2 +-
.../freemarker/core/TemplateClassResolver.java | 4 +-
.../java/freemarker/core/TemplateObject.java | 4 +-
.../java/freemarker/core/TransformBlock.java | 2 +-
src/main/java/freemarker/core/UnifiedCall.java | 4 +-
...nDateTypeFormattingUnsupportedException.java | 2 +-
...nownDateTypeParsingUnsupportedException.java | 2 +-
.../java/freemarker/core/_DelayedAOrAn.java | 2 +-
src/main/java/freemarker/core/_MessageUtil.java | 355 +++++++++++++++++++
21 files changed, 404 insertions(+), 403 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltIn.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index fa316e8..e830cb1 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -400,7 +400,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
protected final void checkMethodArgCount(int argCnt, int expectedCnt) throws TemplateModelException {
if (argCnt != expectedCnt) {
- throw MessageUtil.newArgCntError("?" + key, argCnt, expectedCnt);
+ throw _MessageUtil.newArgCntError("?" + key, argCnt, expectedCnt);
}
}
@@ -410,7 +410,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
protected final void checkMethodArgCount(int argCnt, int minCnt, int maxCnt) throws TemplateModelException {
if (argCnt < minCnt || argCnt > maxCnt) {
- throw MessageUtil.newArgCntError("?" + key, argCnt, minCnt, maxCnt);
+ throw _MessageUtil.newArgCntError("?" + key, argCnt, minCnt, maxCnt);
}
}
@@ -430,7 +430,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
throws TemplateModelException {
TemplateModel arg = (TemplateModel) args.get(argIdx);
if (!(arg instanceof TemplateScalarModel)) {
- throw MessageUtil.newMethodArgMustBeStringException("?" + key, argIdx, arg);
+ throw _MessageUtil.newMethodArgMustBeStringException("?" + key, argIdx, arg);
} else {
return EvalUtil.modelToString((TemplateScalarModel) arg, null, null);
}
@@ -443,18 +443,18 @@ abstract class BuiltIn extends Expression implements Cloneable {
throws TemplateModelException {
TemplateModel arg = (TemplateModel) args.get(argIdx);
if (!(arg instanceof TemplateNumberModel)) {
- throw MessageUtil.newMethodArgMustBeNumberException("?" + key, argIdx, arg);
+ throw _MessageUtil.newMethodArgMustBeNumberException("?" + key, argIdx, arg);
} else {
return EvalUtil.modelToNumber((TemplateNumberModel) arg, null);
}
}
protected final TemplateModelException newMethodArgInvalidValueException(int argIdx, Object[] details) {
- return MessageUtil.newMethodArgInvalidValueException("?" + key, argIdx, details);
+ return _MessageUtil.newMethodArgInvalidValueException("?" + key, argIdx, details);
}
protected final TemplateModelException newMethodArgsInvalidValueException(Object[] details) {
- return MessageUtil.newMethodArgsInvalidValueException("?" + key, details);
+ return _MessageUtil.newMethodArgsInvalidValueException("?" + key, details);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltInsForDates.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForDates.java b/src/main/java/freemarker/core/BuiltInsForDates.java
index ec7d471..5fc0a22 100644
--- a/src/main/java/freemarker/core/BuiltInsForDates.java
+++ b/src/main/java/freemarker/core/BuiltInsForDates.java
@@ -111,7 +111,7 @@ class BuiltInsForDates {
new _DelayedJQuote(tzName));
}
} else {
- throw MessageUtil.newMethodArgUnexpectedTypeException(
+ throw _MessageUtil.newMethodArgUnexpectedTypeException(
"?" + key, 0, "string or java.util.TimeZone", tzArgTM);
}
@@ -193,7 +193,7 @@ class BuiltInsForDates {
throw new _MiscTemplateException(new _ErrorDescriptionBuilder(
"The value of the following has unknown date type, but ?", key,
" needs a value where it's known if it's a date (no time part), time, or date-time value:"
- ).blame(target).tip(MessageUtil.UNKNOWN_DATE_TYPE_ERROR_TIP));
+ ).blame(target).tip(_MessageUtil.UNKNOWN_DATE_TYPE_ERROR_TIP));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltInsForExistenceHandling.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForExistenceHandling.java b/src/main/java/freemarker/core/BuiltInsForExistenceHandling.java
index f25e5dd..9e83d37 100644
--- a/src/main/java/freemarker/core/BuiltInsForExistenceHandling.java
+++ b/src/main/java/freemarker/core/BuiltInsForExistenceHandling.java
@@ -84,7 +84,7 @@ class BuiltInsForExistenceHandling {
new TemplateMethodModelEx() {
public Object exec(List args) throws TemplateModelException {
int argCnt = args.size();
- if (argCnt == 0) throw MessageUtil.newArgCntError("?default", argCnt, 1, Integer.MAX_VALUE);
+ if (argCnt == 0) throw _MessageUtil.newArgCntError("?default", argCnt, 1, Integer.MAX_VALUE);
for (int i = 0; i < argCnt; i++ ) {
TemplateModel result = (TemplateModel) args.get(i);
if (result != null) return result;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
index 2adcebc..e0640c2 100644
--- a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
+++ b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
@@ -587,7 +587,7 @@ class BuiltInsForMultipleTypes {
if (cachedValue == null) {
if (defaultFormat == null) {
if (dateModel.getDateType() == TemplateDateModel.UNKNOWN) {
- throw MessageUtil.newCantFormatUnknownTypeDateException(target, null);
+ throw _MessageUtil.newCantFormatUnknownTypeDateException(target, null);
} else {
throw new BugException();
}
@@ -596,7 +596,7 @@ class BuiltInsForMultipleTypes {
cachedValue = EvalUtil.assertFormatResultNotNull(defaultFormat.formatToPlainText(dateModel));
} catch (TemplateValueFormatException e) {
try {
- throw MessageUtil.newCantFormatDateException(defaultFormat, target, e, true);
+ throw _MessageUtil.newCantFormatDateException(defaultFormat, target, e, true);
} catch (TemplateException e2) {
// `e` should always be a TemplateModelException here, but to be sure:
throw _CoreAPI.ensureIsTemplateModelException("Failed to format date/time/datetime", e2);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/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 f2d1c6a..a58c7f6 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -214,9 +214,9 @@ class BuiltInsForSequences {
} catch (TemplateException e) {
throw new _TemplateModelException(e,
"\"?", key, "\" failed at index ", Integer.valueOf(idx), " with this error:\n\n",
- MessageUtil.EMBEDDED_MESSAGE_BEGIN,
+ _MessageUtil.EMBEDDED_MESSAGE_BEGIN,
new _DelayedGetMessageWithoutStackTop(e),
- MessageUtil.EMBEDDED_MESSAGE_END);
+ _MessageUtil.EMBEDDED_MESSAGE_END);
}
}
idx++;
@@ -527,7 +527,7 @@ class BuiltInsForSequences {
// Should be:
// checkMethodArgCount(args, 1);
// But for BC:
- if (args.size() < 1) throw MessageUtil.newArgCntError("?" + key, args.size(), 1);
+ if (args.size() < 1) throw _MessageUtil.newArgCntError("?" + key, args.size(), 1);
String[] subvars;
Object obj = args.get(0);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltInsForStringsBasic.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForStringsBasic.java b/src/main/java/freemarker/core/BuiltInsForStringsBasic.java
index 77f64ec..abb3530 100644
--- a/src/main/java/freemarker/core/BuiltInsForStringsBasic.java
+++ b/src/main/java/freemarker/core/BuiltInsForStringsBasic.java
@@ -604,7 +604,7 @@ class BuiltInsForStringsBasic {
throw newIndexGreaterThanLengthException(1, endIdx, len);
}
if (beginIdx > endIdx) {
- throw MessageUtil.newMethodArgsInvalidValueException("?" + key,
+ throw _MessageUtil.newMethodArgsInvalidValueException("?" + key,
"The begin index argument, ", Integer.valueOf(beginIdx),
", shouldn't be greater than the end index argument, ",
Integer.valueOf(endIdx), ".");
@@ -617,7 +617,7 @@ class BuiltInsForStringsBasic {
private TemplateModelException newIndexGreaterThanLengthException(
int argIdx, int idx, final int len) throws TemplateModelException {
- return MessageUtil.newMethodArgInvalidValueException(
+ return _MessageUtil.newMethodArgInvalidValueException(
"?" + key, argIdx,
"The index mustn't be greater than the length of the string, ",
Integer.valueOf(len),
@@ -626,7 +626,7 @@ class BuiltInsForStringsBasic {
private TemplateModelException newIndexLessThan0Exception(
int argIdx, int idx) throws TemplateModelException {
- return MessageUtil.newMethodArgInvalidValueException(
+ return _MessageUtil.newMethodArgInvalidValueException(
"?" + key, argIdx,
"The index must be at least 0, but was ", Integer.valueOf(idx), ".");
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/BuiltInsForStringsMisc.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForStringsMisc.java b/src/main/java/freemarker/core/BuiltInsForStringsMisc.java
index 4073235..e4b18a2 100644
--- a/src/main/java/freemarker/core/BuiltInsForStringsMisc.java
+++ b/src/main/java/freemarker/core/BuiltInsForStringsMisc.java
@@ -89,9 +89,9 @@ class BuiltInsForStringsMisc {
} catch (ParseException e) {
throw new _MiscTemplateException(this, env,
"Failed to \"?", key, "\" string with this error:\n\n",
- MessageUtil.EMBEDDED_MESSAGE_BEGIN,
+ _MessageUtil.EMBEDDED_MESSAGE_BEGIN,
new _DelayedGetMessage(e),
- MessageUtil.EMBEDDED_MESSAGE_END,
+ _MessageUtil.EMBEDDED_MESSAGE_END,
"\n\nThe failing expression:");
}
try {
@@ -99,9 +99,9 @@ class BuiltInsForStringsMisc {
} catch (TemplateException e) {
throw new _MiscTemplateException(e, this, env,
"Failed to \"?", key, "\" string with this error:\n\n",
- MessageUtil.EMBEDDED_MESSAGE_BEGIN,
+ _MessageUtil.EMBEDDED_MESSAGE_BEGIN,
new _DelayedGetMessageWithoutStackTop(e),
- MessageUtil.EMBEDDED_MESSAGE_END,
+ _MessageUtil.EMBEDDED_MESSAGE_END,
"\n\nThe failing expression:");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 47b390a..cc62d4c 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1149,7 +1149,7 @@ public final class Environment extends Configurable {
try {
return EvalUtil.assertFormatResultNotNull(format.formatToPlainText(number));
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatNumberException(format, exp, e, useTempModelExc);
+ throw _MessageUtil.newCantFormatNumberException(format, exp, e, useTempModelExc);
}
}
@@ -1424,7 +1424,7 @@ public final class Environment extends Configurable {
try {
return EvalUtil.assertFormatResultNotNull(format.formatToPlainText(tdm));
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatDateException(format, tdmSourceExpr, e, useTempModelExc);
+ throw _MessageUtil.newCantFormatDateException(format, tdmSourceExpr, e, useTempModelExc);
}
}
@@ -1447,7 +1447,7 @@ public final class Environment extends Configurable {
try {
return EvalUtil.assertFormatResultNotNull(format.formatToPlainText(tdm));
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatDateException(format, blamedDateSourceExp, e, useTempModelExc);
+ throw _MessageUtil.newCantFormatDateException(format, blamedDateSourceExp, e, useTempModelExc);
}
}
@@ -1634,7 +1634,7 @@ public final class Environment extends Configurable {
try {
return getTemplateDateFormat(dateType, dateClass);
} catch (UnknownDateTypeFormattingUnsupportedException e) {
- throw MessageUtil.newCantFormatUnknownTypeDateException(blamedDateSourceExp, e);
+ throw _MessageUtil.newCantFormatUnknownTypeDateException(blamedDateSourceExp, e);
} catch (TemplateValueFormatException e) {
String settingName;
String settingValue;
@@ -1677,7 +1677,7 @@ public final class Environment extends Configurable {
try {
return getTemplateDateFormat(formatString, dateType, dateClass);
} catch (UnknownDateTypeFormattingUnsupportedException e) {
- throw MessageUtil.newCantFormatUnknownTypeDateException(blamedDateSourceExp, e);
+ throw _MessageUtil.newCantFormatUnknownTypeDateException(blamedDateSourceExp, e);
} catch (TemplateValueFormatException e) {
_ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
"Can't create date/time/datetime format based on format string ",
@@ -2182,15 +2182,15 @@ public final class Environment extends Configurable {
}
static void appendInstructionStackItem(TemplateElement stackEl, StringBuilder sb) {
- sb.append(MessageUtil.shorten(stackEl.getDescription(), 40));
+ sb.append(_MessageUtil.shorten(stackEl.getDescription(), 40));
sb.append(" [");
Macro enclosingMacro = getEnclosingMacro(stackEl);
if (enclosingMacro != null) {
- sb.append(MessageUtil.formatLocationForEvaluationError(
+ sb.append(_MessageUtil.formatLocationForEvaluationError(
enclosingMacro, stackEl.beginLine, stackEl.beginColumn));
} else {
- sb.append(MessageUtil.formatLocationForEvaluationError(
+ sb.append(_MessageUtil.formatLocationForEvaluationError(
stackEl.getTemplate(), stackEl.beginLine, stackEl.beginColumn));
}
sb.append("]");
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/EvalUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/EvalUtil.java b/src/main/java/freemarker/core/EvalUtil.java
index 4b03e27..ebde9c3 100644
--- a/src/main/java/freemarker/core/EvalUtil.java
+++ b/src/main/java/freemarker/core/EvalUtil.java
@@ -373,7 +373,7 @@ class EvalUtil {
try {
return assertFormatResultNotNull(format.format(tnm));
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatNumberException(format, exp, e, false);
+ throw _MessageUtil.newCantFormatNumberException(format, exp, e, false);
}
} else if (tm instanceof TemplateDateModel) {
TemplateDateModel tdm = (TemplateDateModel) tm;
@@ -381,7 +381,7 @@ class EvalUtil {
try {
return assertFormatResultNotNull(format.format(tdm));
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatDateException(format, exp, e, false);
+ throw _MessageUtil.newCantFormatDateException(format, exp, e, false);
}
} else if (tm instanceof TemplateMarkupOutputModel) {
return tm;
@@ -408,7 +408,7 @@ class EvalUtil {
try {
return ensureFormatResultString(format.format(tnm), exp, env);
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatNumberException(format, exp, e, false);
+ throw _MessageUtil.newCantFormatNumberException(format, exp, e, false);
}
} else if (tm instanceof TemplateDateModel) {
TemplateDateModel tdm = (TemplateDateModel) tm;
@@ -416,7 +416,7 @@ class EvalUtil {
try {
return ensureFormatResultString(format.format(tdm), exp, env);
} catch (TemplateValueFormatException e) {
- throw MessageUtil.newCantFormatDateException(format, exp, e, false);
+ throw _MessageUtil.newCantFormatDateException(format, exp, e, false);
}
} else {
return coerceModelToTextualCommon(tm, exp, seqTip, false, false, env);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/Interpret.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Interpret.java b/src/main/java/freemarker/core/Interpret.java
index a2cff1c..7252a2f 100644
--- a/src/main/java/freemarker/core/Interpret.java
+++ b/src/main/java/freemarker/core/Interpret.java
@@ -100,9 +100,9 @@ class Interpret extends OutputFormatBoundBuiltIn {
} catch (IOException e) {
throw new _MiscTemplateException(this, e, env, new Object[] {
"Template parsing with \"?", key, "\" has failed with this error:\n\n",
- MessageUtil.EMBEDDED_MESSAGE_BEGIN,
+ _MessageUtil.EMBEDDED_MESSAGE_BEGIN,
new _DelayedGetMessage(e),
- MessageUtil.EMBEDDED_MESSAGE_END,
+ _MessageUtil.EMBEDDED_MESSAGE_END,
"\n\nThe failed expression:" });
}
@@ -131,9 +131,9 @@ class Interpret extends OutputFormatBoundBuiltIn {
} catch (Exception e) {
throw new _TemplateModelException(e,
"Template created with \"?", key, "\" has stopped with this error:\n\n",
- MessageUtil.EMBEDDED_MESSAGE_BEGIN,
+ _MessageUtil.EMBEDDED_MESSAGE_BEGIN,
new _DelayedGetMessage(e),
- MessageUtil.EMBEDDED_MESSAGE_END);
+ _MessageUtil.EMBEDDED_MESSAGE_END);
}
return new Writer(out)
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/Macro.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Macro.java b/src/main/java/freemarker/core/Macro.java
index fdce23b..2ea9c2c 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -119,7 +119,7 @@ public final class Macro extends TemplateElement implements TemplateModel {
if (function) {
sb.append(defaultExpr.getCanonicalForm());
} else {
- MessageUtil.appendExpressionAsUntearable(sb, defaultExpr);
+ _MessageUtil.appendExpressionAsUntearable(sb, defaultExpr);
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/MessageUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/MessageUtil.java b/src/main/java/freemarker/core/MessageUtil.java
deleted file mode 100644
index 418ad26..0000000
--- a/src/main/java/freemarker/core/MessageUtil.java
+++ /dev/null
@@ -1,354 +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.core;
-
-import java.util.ArrayList;
-
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-import freemarker.template.utility.StringUtil;
-
-/**
- * Utilities for creating error messages (and other messages).
- */
-class MessageUtil {
-
- static final String UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE
- = "Can't convert the date-like value to string because it isn't "
- + "known if it's a date (no time part), time or date-time value.";
-
- static final String UNKNOWN_DATE_PARSING_ERROR_MESSAGE
- = "Can't parse the string to date-like value because it isn't "
- + "known if it's desired result should be a date (no time part), a time, or a date-time value.";
-
- static final String UNKNOWN_DATE_TYPE_ERROR_TIP =
- "Use ?date, ?time, or ?datetime to tell FreeMarker the exact type.";
-
- static final Object[] UNKNOWN_DATE_TO_STRING_TIPS = {
- UNKNOWN_DATE_TYPE_ERROR_TIP,
- "If you need a particular format only once, use ?string(pattern), like ?string('dd.MM.yyyy HH:mm:ss'), "
- + "to specify which fields to display. "
- };
-
- static final String EMBEDDED_MESSAGE_BEGIN = "---begin-message---\n";
-
- static final String EMBEDDED_MESSAGE_END = "\n---end-message---";
-
- // Can't be instantiated
- private MessageUtil() { }
-
- static String formatLocationForSimpleParsingError(Template template, int line, int column) {
- return formatLocation("in", template, line, column);
- }
-
- static String formatLocationForSimpleParsingError(String templateSourceName, int line, int column) {
- return formatLocation("in", templateSourceName, line, column);
- }
-
- static String formatLocationForDependentParsingError(Template template, int line, int column) {
- return formatLocation("on", template, line, column);
- }
-
- static String formatLocationForDependentParsingError(String templateSourceName, int line, int column) {
- return formatLocation("on", templateSourceName, line, column);
- }
-
- static String formatLocationForEvaluationError(Template template, int line, int column) {
- return formatLocation("at", template, line, column);
- }
-
- static String formatLocationForEvaluationError(Macro macro, int line, int column) {
- Template t = macro.getTemplate();
- return formatLocation("at", t != null ? t.getSourceName() : null, macro.getName(), macro.isFunction(), line, column);
- }
-
- static String formatLocationForEvaluationError(String templateSourceName, int line, int column) {
- return formatLocation("at", templateSourceName, line, column);
- }
-
- private static String formatLocation(String preposition, Template template, int line, int column) {
- return formatLocation(preposition, template != null ? template.getSourceName() : null, line, column);
- }
-
- private static String formatLocation(String preposition, String templateSourceName, int line, int column) {
- return formatLocation(
- preposition, templateSourceName,
- null, false,
- line, column);
- }
-
- private static String formatLocation(
- String preposition, String templateSourceName,
- String macroOrFuncName, boolean isFunction,
- int line, int column) {
- String templateDesc;
- if (line < 0) {
- templateDesc = "?eval-ed string";
- macroOrFuncName = null;
- } else {
- templateDesc = templateSourceName != null
- ? "template " + StringUtil.jQuoteNoXSS(templateSourceName)
- : "nameless template";
- }
- return "in " + templateDesc
- + (macroOrFuncName != null
- ? " in " + (isFunction ? "function " : "macro ") + StringUtil.jQuote(macroOrFuncName)
- : "")
- + " "
- + preposition + " " + formatPosition(line, column);
- }
-
- static String formatPosition(int line, int column) {
- return "line " + (line >= 0 ? line : line - (TemplateObject.RUNTIME_EVAL_LINE_DISPLACEMENT - 1))
- + ", column " + column;
- }
-
- /**
- * Returns a single line string that is no longer than {@code maxLength}.
- * If will truncate the string at line-breaks too.
- * The truncation is always signaled with a a {@code "..."} at the end of the result string.
- */
- static String shorten(String s, int maxLength) {
- if (maxLength < 5) maxLength = 5;
-
- boolean isTruncated = false;
-
- int brIdx = s.indexOf('\n');
- if (brIdx != -1) {
- s = s.substring(0, brIdx);
- isTruncated = true;
- };
- brIdx = s.indexOf('\r');
- if (brIdx != -1) {
- s = s.substring(0, brIdx);
- isTruncated = true;
- }
-
- if (s.length() > maxLength) {
- s = s.substring(0, maxLength - 3);
- isTruncated = true;
- }
-
- if (!isTruncated) {
- return s;
- } else {
- if (s.endsWith(".")) {
- if (s.endsWith("..")) {
- if (s.endsWith("...")) {
- return s;
- } else {
- return s + ".";
- }
- } else {
- return s + "..";
- }
- } else {
- return s + "...";
- }
- }
- }
-
- static StringBuilder appendExpressionAsUntearable(StringBuilder sb, Expression argExp) {
- boolean needParen =
- !(argExp instanceof NumberLiteral)
- && !(argExp instanceof StringLiteral)
- && !(argExp instanceof BooleanLiteral)
- && !(argExp instanceof ListLiteral)
- && !(argExp instanceof HashLiteral)
- && !(argExp instanceof Identifier)
- && !(argExp instanceof Dot)
- && !(argExp instanceof DynamicKeyName)
- && !(argExp instanceof MethodCall)
- && !(argExp instanceof BuiltIn)
- && !(argExp instanceof ExistsExpression)
- && !(argExp instanceof ParentheticalExpression);
- if (needParen) sb.append('(');
- sb.append(argExp.getCanonicalForm());
- if (needParen) sb.append(')');
- return sb;
- }
-
- static TemplateModelException newArgCntError(String methodName, int argCnt, int expectedCnt) {
- return newArgCntError(methodName, argCnt, expectedCnt, expectedCnt);
- }
-
- static TemplateModelException newArgCntError(String methodName, int argCnt, int minCnt, int maxCnt) {
- ArrayList/*<Object>*/ desc = new ArrayList(20);
-
- desc.add(methodName);
-
- desc.add("(");
- if (maxCnt != 0) desc.add("...");
- desc.add(") expects ");
-
- if (minCnt == maxCnt) {
- if (maxCnt == 0) {
- desc.add("no");
- } else {
- desc.add(Integer.valueOf(maxCnt));
- }
- } else if (maxCnt - minCnt == 1) {
- desc.add(Integer.valueOf(minCnt));
- desc.add(" or ");
- desc.add(Integer.valueOf(maxCnt));
- } else {
- desc.add(Integer.valueOf(minCnt));
- if (maxCnt != Integer.MAX_VALUE) {
- desc.add(" to ");
- desc.add(Integer.valueOf(maxCnt));
- } else {
- desc.add(" or more (unlimited)");
- }
- }
- desc.add(" argument");
- if (maxCnt > 1) desc.add("s");
-
- desc.add(" but has received ");
- if (argCnt == 0) {
- desc.add("none");
- } else {
- desc.add(Integer.valueOf(argCnt));
- }
- desc.add(".");
-
- return new _TemplateModelException(desc.toArray());
- }
-
- static TemplateModelException newMethodArgMustBeStringException(String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "string", arg);
- }
-
- static TemplateModelException newMethodArgMustBeNumberException(String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "number", arg);
- }
-
- static TemplateModelException newMethodArgMustBeBooleanException(String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "boolean", arg);
- }
-
- static TemplateModelException newMethodArgMustBeExtendedHashException(
- String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "extended hash", arg);
- }
-
- static TemplateModelException newMethodArgMustBeSequenceException(
- String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence", arg);
- }
-
- static TemplateModelException newMethodArgMustBeSequenceOrCollectionException(
- String methodName, int argIdx, TemplateModel arg) {
- return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence or collection", arg);
- }
-
- static TemplateModelException newMethodArgUnexpectedTypeException(
- String methodName, int argIdx, String expectedType, TemplateModel arg) {
- return new _TemplateModelException(
- methodName, "(...) expects ", new _DelayedAOrAn(expectedType), " as argument #", Integer.valueOf(argIdx + 1),
- ", but received ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(arg)), ".");
- }
-
- /**
- * The type of the argument was good, but it's value wasn't.
- */
- static TemplateModelException newMethodArgInvalidValueException(
- String methodName, int argIdx, Object... details) {
- return new _TemplateModelException(
- methodName, "(...) argument #", Integer.valueOf(argIdx + 1),
- " had invalid value: ", details);
- }
-
- /**
- * The type of the argument was good, but the values of two or more arguments are inconsistent with each other.
- */
- static TemplateModelException newMethodArgsInvalidValueException(
- String methodName, Object... details) {
- return new _TemplateModelException(methodName, "(...) arguments have invalid value: ", details);
- }
-
- static TemplateException newInstantiatingClassNotAllowedException(String className, Environment env) {
- return new _MiscTemplateException(env,
- "Instantiating ", className, " is not allowed in the template for security reasons.");
- }
-
- static _TemplateModelException newCantFormatUnknownTypeDateException(
- Expression dateSourceExpr, UnknownDateTypeFormattingUnsupportedException cause) {
- return new _TemplateModelException(cause, null, new _ErrorDescriptionBuilder(
- MessageUtil.UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE)
- .blame(dateSourceExpr)
- .tips(MessageUtil.UNKNOWN_DATE_TO_STRING_TIPS));
- }
-
- static TemplateException newCantFormatDateException(TemplateDateFormat format, Expression dataSrcExp,
- TemplateValueFormatException e, boolean useTempModelExc) {
- _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
- "Failed to format date/time/datetime with format ", new _DelayedJQuote(format.getDescription()), ": ",
- e.getMessage())
- .blame(dataSrcExp);
- return useTempModelExc
- ? new _TemplateModelException(e, (Environment) null, desc)
- : new _MiscTemplateException(e, (Environment) null, desc);
- }
-
- static TemplateException newCantFormatNumberException(TemplateNumberFormat format, Expression dataSrcExp,
- TemplateValueFormatException e, boolean useTempModelExc) {
- _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
- "Failed to format number with format ", new _DelayedJQuote(format.getDescription()), ": ",
- e.getMessage())
- .blame(dataSrcExp);
- return useTempModelExc
- ? new _TemplateModelException(e, (Environment) null, desc)
- : new _MiscTemplateException(e, (Environment) null, desc);
- }
-
- /**
- * @return "a" or "an" or "a(n)" (or "" for empty string) for an FTL type name
- */
- static String getAOrAn(String s) {
- if (s == null) return null;
- if (s.length() == 0) return "";
-
- char fc = Character.toLowerCase(s.charAt(0));
- if (fc == 'a' || fc == 'e' || fc == 'i') {
- return "an";
- } else if (fc == 'h') {
- String ls = s.toLowerCase();
- if (ls.startsWith("has") || ls.startsWith("hi")) {
- return "a";
- } else if (ls.startsWith("ht")) {
- return "an";
- } else {
- return "a(n)";
- }
- } else if (fc == 'u' || fc == 'o') {
- return "a(n)";
- } else {
- char sc = (s.length() > 1) ? s.charAt(1) : '\0';
- if (fc == 'x' && !(sc == 'a' || sc == 'e' || sc == 'i' || sc == 'a' || sc == 'o' || sc == 'u')) {
- return "an";
- } else {
- return "a";
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/ParseException.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ParseException.java b/src/main/java/freemarker/core/ParseException.java
index 8aa5049..985c783 100644
--- a/src/main/java/freemarker/core/ParseException.java
+++ b/src/main/java/freemarker/core/ParseException.java
@@ -333,7 +333,7 @@ public class ParseException extends IOException implements FMParserConstants {
String prefix;
if (!isInJBossToolsMode()) {
prefix = "Syntax error "
- + MessageUtil.formatLocationForSimpleParsingError(templateName, lineNumber, columnNumber)
+ + _MessageUtil.formatLocationForSimpleParsingError(templateName, lineNumber, columnNumber)
+ ":\n";
} else {
prefix = "[col. " + columnNumber + "] ";
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/TemplateClassResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateClassResolver.java b/src/main/java/freemarker/core/TemplateClassResolver.java
index e02b022..67c5720 100644
--- a/src/main/java/freemarker/core/TemplateClassResolver.java
+++ b/src/main/java/freemarker/core/TemplateClassResolver.java
@@ -66,7 +66,7 @@ public interface TemplateClassResolver {
if (className.equals(ObjectConstructor.class.getName())
|| className.equals(Execute.class.getName())
|| className.equals("freemarker.template.utility.JythonRuntime")) {
- throw MessageUtil.newInstantiatingClassNotAllowedException(className, env);
+ throw _MessageUtil.newInstantiatingClassNotAllowedException(className, env);
}
try {
return ClassUtil.forName(className);
@@ -84,7 +84,7 @@ public interface TemplateClassResolver {
public Class resolve(String className, Environment env, Template template)
throws TemplateException {
- throw MessageUtil.newInstantiatingClassNotAllowedException(className, env);
+ throw _MessageUtil.newInstantiatingClassNotAllowedException(className, env);
}
};
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/TemplateObject.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateObject.java b/src/main/java/freemarker/core/TemplateObject.java
index 248395d..18355d9 100644
--- a/src/main/java/freemarker/core/TemplateObject.java
+++ b/src/main/java/freemarker/core/TemplateObject.java
@@ -98,7 +98,7 @@ public abstract class TemplateObject {
* where in the template source, this object is.
*/
public String getStartLocation() {
- return MessageUtil.formatLocationForEvaluationError(template, beginLine, beginColumn);
+ return _MessageUtil.formatLocationForEvaluationError(template, beginLine, beginColumn);
}
/**
@@ -110,7 +110,7 @@ public abstract class TemplateObject {
}
public String getEndLocation() {
- return MessageUtil.formatLocationForEvaluationError(template, endLine, endColumn);
+ return _MessageUtil.formatLocationForEvaluationError(template, endLine, endColumn);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/TransformBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TransformBlock.java b/src/main/java/freemarker/core/TransformBlock.java
index 6b78fa8..78a7b87 100644
--- a/src/main/java/freemarker/core/TransformBlock.java
+++ b/src/main/java/freemarker/core/TransformBlock.java
@@ -95,7 +95,7 @@ final class TransformBlock extends TemplateElement {
sb.append(' ');
sb.append(entry.getKey());
sb.append('=');
- MessageUtil.appendExpressionAsUntearable(sb, (Expression) entry.getValue());
+ _MessageUtil.appendExpressionAsUntearable(sb, (Expression) entry.getValue());
}
}
if (canonical) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/UnifiedCall.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnifiedCall.java b/src/main/java/freemarker/core/UnifiedCall.java
index ee0334d..f445cd3 100644
--- a/src/main/java/freemarker/core/UnifiedCall.java
+++ b/src/main/java/freemarker/core/UnifiedCall.java
@@ -116,7 +116,7 @@ final class UnifiedCall extends TemplateElement implements DirectiveCallPlace {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
sb.append('@');
- MessageUtil.appendExpressionAsUntearable(sb, nameExp);
+ _MessageUtil.appendExpressionAsUntearable(sb, nameExp);
boolean nameIsInParen = sb.charAt(sb.length() - 1) == ')';
if (positionalArgs != null) {
for (int i = 0; i < positionalArgs.size(); i++) {
@@ -135,7 +135,7 @@ final class UnifiedCall extends TemplateElement implements DirectiveCallPlace {
sb.append(' ');
sb.append(_CoreStringUtils.toFTLTopLevelIdentifierReference((String) entry.getKey()));
sb.append('=');
- MessageUtil.appendExpressionAsUntearable(sb, argExp);
+ _MessageUtil.appendExpressionAsUntearable(sb, argExp);
}
}
if (bodyParameterNames != null && !bodyParameterNames.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/UnknownDateTypeFormattingUnsupportedException.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnknownDateTypeFormattingUnsupportedException.java b/src/main/java/freemarker/core/UnknownDateTypeFormattingUnsupportedException.java
index 01a0871..0a4e175 100644
--- a/src/main/java/freemarker/core/UnknownDateTypeFormattingUnsupportedException.java
+++ b/src/main/java/freemarker/core/UnknownDateTypeFormattingUnsupportedException.java
@@ -29,7 +29,7 @@ import freemarker.template.TemplateDateModel;
public final class UnknownDateTypeFormattingUnsupportedException extends UnformattableValueException {
public UnknownDateTypeFormattingUnsupportedException() {
- super(MessageUtil.UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE);
+ super(_MessageUtil.UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/UnknownDateTypeParsingUnsupportedException.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnknownDateTypeParsingUnsupportedException.java b/src/main/java/freemarker/core/UnknownDateTypeParsingUnsupportedException.java
index e9edf95..2d15132 100644
--- a/src/main/java/freemarker/core/UnknownDateTypeParsingUnsupportedException.java
+++ b/src/main/java/freemarker/core/UnknownDateTypeParsingUnsupportedException.java
@@ -30,7 +30,7 @@ import freemarker.template.TemplateDateModel;
public final class UnknownDateTypeParsingUnsupportedException extends UnformattableValueException {
public UnknownDateTypeParsingUnsupportedException() {
- super(MessageUtil.UNKNOWN_DATE_PARSING_ERROR_MESSAGE);
+ super(_MessageUtil.UNKNOWN_DATE_PARSING_ERROR_MESSAGE);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/_DelayedAOrAn.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/_DelayedAOrAn.java b/src/main/java/freemarker/core/_DelayedAOrAn.java
index 21bc896..8d7306e 100644
--- a/src/main/java/freemarker/core/_DelayedAOrAn.java
+++ b/src/main/java/freemarker/core/_DelayedAOrAn.java
@@ -29,7 +29,7 @@ public class _DelayedAOrAn extends _DelayedConversionToString {
@Override
protected String doConversion(Object obj) {
String s = obj.toString();
- return MessageUtil.getAOrAn(s) + " " + s;
+ return _MessageUtil.getAOrAn(s) + " " + s;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d7c654db/src/main/java/freemarker/core/_MessageUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/_MessageUtil.java b/src/main/java/freemarker/core/_MessageUtil.java
new file mode 100644
index 0000000..a84eb9d
--- /dev/null
+++ b/src/main/java/freemarker/core/_MessageUtil.java
@@ -0,0 +1,355 @@
+/*
+ * 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.core;
+
+import java.util.ArrayList;
+
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.utility.StringUtil;
+
+/**
+ * Used internally only, might changes without notice!
+ * Utilities for creating error messages (and other messages).
+ */
+public class _MessageUtil {
+
+ static final String UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE
+ = "Can't convert the date-like value to string because it isn't "
+ + "known if it's a date (no time part), time or date-time value.";
+
+ static final String UNKNOWN_DATE_PARSING_ERROR_MESSAGE
+ = "Can't parse the string to date-like value because it isn't "
+ + "known if it's desired result should be a date (no time part), a time, or a date-time value.";
+
+ static final String UNKNOWN_DATE_TYPE_ERROR_TIP =
+ "Use ?date, ?time, or ?datetime to tell FreeMarker the exact type.";
+
+ static final Object[] UNKNOWN_DATE_TO_STRING_TIPS = {
+ UNKNOWN_DATE_TYPE_ERROR_TIP,
+ "If you need a particular format only once, use ?string(pattern), like ?string('dd.MM.yyyy HH:mm:ss'), "
+ + "to specify which fields to display. "
+ };
+
+ static final String EMBEDDED_MESSAGE_BEGIN = "---begin-message---\n";
+
+ static final String EMBEDDED_MESSAGE_END = "\n---end-message---";
+
+ // Can't be instantiated
+ private _MessageUtil() { }
+
+ static String formatLocationForSimpleParsingError(Template template, int line, int column) {
+ return formatLocation("in", template, line, column);
+ }
+
+ static String formatLocationForSimpleParsingError(String templateSourceName, int line, int column) {
+ return formatLocation("in", templateSourceName, line, column);
+ }
+
+ static String formatLocationForDependentParsingError(Template template, int line, int column) {
+ return formatLocation("on", template, line, column);
+ }
+
+ static String formatLocationForDependentParsingError(String templateSourceName, int line, int column) {
+ return formatLocation("on", templateSourceName, line, column);
+ }
+
+ static String formatLocationForEvaluationError(Template template, int line, int column) {
+ return formatLocation("at", template, line, column);
+ }
+
+ static String formatLocationForEvaluationError(Macro macro, int line, int column) {
+ Template t = macro.getTemplate();
+ return formatLocation("at", t != null ? t.getSourceName() : null, macro.getName(), macro.isFunction(), line, column);
+ }
+
+ static String formatLocationForEvaluationError(String templateSourceName, int line, int column) {
+ return formatLocation("at", templateSourceName, line, column);
+ }
+
+ private static String formatLocation(String preposition, Template template, int line, int column) {
+ return formatLocation(preposition, template != null ? template.getSourceName() : null, line, column);
+ }
+
+ private static String formatLocation(String preposition, String templateSourceName, int line, int column) {
+ return formatLocation(
+ preposition, templateSourceName,
+ null, false,
+ line, column);
+ }
+
+ private static String formatLocation(
+ String preposition, String templateSourceName,
+ String macroOrFuncName, boolean isFunction,
+ int line, int column) {
+ String templateDesc;
+ if (line < 0) {
+ templateDesc = "?eval-ed string";
+ macroOrFuncName = null;
+ } else {
+ templateDesc = templateSourceName != null
+ ? "template " + StringUtil.jQuoteNoXSS(templateSourceName)
+ : "nameless template";
+ }
+ return "in " + templateDesc
+ + (macroOrFuncName != null
+ ? " in " + (isFunction ? "function " : "macro ") + StringUtil.jQuote(macroOrFuncName)
+ : "")
+ + " "
+ + preposition + " " + formatPosition(line, column);
+ }
+
+ static String formatPosition(int line, int column) {
+ return "line " + (line >= 0 ? line : line - (TemplateObject.RUNTIME_EVAL_LINE_DISPLACEMENT - 1))
+ + ", column " + column;
+ }
+
+ /**
+ * Returns a single line string that is no longer than {@code maxLength}.
+ * If will truncate the string at line-breaks too.
+ * The truncation is always signaled with a a {@code "..."} at the end of the result string.
+ */
+ static String shorten(String s, int maxLength) {
+ if (maxLength < 5) maxLength = 5;
+
+ boolean isTruncated = false;
+
+ int brIdx = s.indexOf('\n');
+ if (brIdx != -1) {
+ s = s.substring(0, brIdx);
+ isTruncated = true;
+ };
+ brIdx = s.indexOf('\r');
+ if (brIdx != -1) {
+ s = s.substring(0, brIdx);
+ isTruncated = true;
+ }
+
+ if (s.length() > maxLength) {
+ s = s.substring(0, maxLength - 3);
+ isTruncated = true;
+ }
+
+ if (!isTruncated) {
+ return s;
+ } else {
+ if (s.endsWith(".")) {
+ if (s.endsWith("..")) {
+ if (s.endsWith("...")) {
+ return s;
+ } else {
+ return s + ".";
+ }
+ } else {
+ return s + "..";
+ }
+ } else {
+ return s + "...";
+ }
+ }
+ }
+
+ static StringBuilder appendExpressionAsUntearable(StringBuilder sb, Expression argExp) {
+ boolean needParen =
+ !(argExp instanceof NumberLiteral)
+ && !(argExp instanceof StringLiteral)
+ && !(argExp instanceof BooleanLiteral)
+ && !(argExp instanceof ListLiteral)
+ && !(argExp instanceof HashLiteral)
+ && !(argExp instanceof Identifier)
+ && !(argExp instanceof Dot)
+ && !(argExp instanceof DynamicKeyName)
+ && !(argExp instanceof MethodCall)
+ && !(argExp instanceof BuiltIn)
+ && !(argExp instanceof ExistsExpression)
+ && !(argExp instanceof ParentheticalExpression);
+ if (needParen) sb.append('(');
+ sb.append(argExp.getCanonicalForm());
+ if (needParen) sb.append(')');
+ return sb;
+ }
+
+ static TemplateModelException newArgCntError(String methodName, int argCnt, int expectedCnt) {
+ return newArgCntError(methodName, argCnt, expectedCnt, expectedCnt);
+ }
+
+ static TemplateModelException newArgCntError(String methodName, int argCnt, int minCnt, int maxCnt) {
+ ArrayList/*<Object>*/ desc = new ArrayList(20);
+
+ desc.add(methodName);
+
+ desc.add("(");
+ if (maxCnt != 0) desc.add("...");
+ desc.add(") expects ");
+
+ if (minCnt == maxCnt) {
+ if (maxCnt == 0) {
+ desc.add("no");
+ } else {
+ desc.add(Integer.valueOf(maxCnt));
+ }
+ } else if (maxCnt - minCnt == 1) {
+ desc.add(Integer.valueOf(minCnt));
+ desc.add(" or ");
+ desc.add(Integer.valueOf(maxCnt));
+ } else {
+ desc.add(Integer.valueOf(minCnt));
+ if (maxCnt != Integer.MAX_VALUE) {
+ desc.add(" to ");
+ desc.add(Integer.valueOf(maxCnt));
+ } else {
+ desc.add(" or more (unlimited)");
+ }
+ }
+ desc.add(" argument");
+ if (maxCnt > 1) desc.add("s");
+
+ desc.add(" but has received ");
+ if (argCnt == 0) {
+ desc.add("none");
+ } else {
+ desc.add(Integer.valueOf(argCnt));
+ }
+ desc.add(".");
+
+ return new _TemplateModelException(desc.toArray());
+ }
+
+ static TemplateModelException newMethodArgMustBeStringException(String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "string", arg);
+ }
+
+ static TemplateModelException newMethodArgMustBeNumberException(String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "number", arg);
+ }
+
+ static TemplateModelException newMethodArgMustBeBooleanException(String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "boolean", arg);
+ }
+
+ static TemplateModelException newMethodArgMustBeExtendedHashException(
+ String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "extended hash", arg);
+ }
+
+ static TemplateModelException newMethodArgMustBeSequenceException(
+ String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence", arg);
+ }
+
+ static TemplateModelException newMethodArgMustBeSequenceOrCollectionException(
+ String methodName, int argIdx, TemplateModel arg) {
+ return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence or collection", arg);
+ }
+
+ static TemplateModelException newMethodArgUnexpectedTypeException(
+ String methodName, int argIdx, String expectedType, TemplateModel arg) {
+ return new _TemplateModelException(
+ methodName, "(...) expects ", new _DelayedAOrAn(expectedType), " as argument #", Integer.valueOf(argIdx + 1),
+ ", but received ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(arg)), ".");
+ }
+
+ /**
+ * The type of the argument was good, but it's value wasn't.
+ */
+ static TemplateModelException newMethodArgInvalidValueException(
+ String methodName, int argIdx, Object... details) {
+ return new _TemplateModelException(
+ methodName, "(...) argument #", Integer.valueOf(argIdx + 1),
+ " had invalid value: ", details);
+ }
+
+ /**
+ * The type of the argument was good, but the values of two or more arguments are inconsistent with each other.
+ */
+ static TemplateModelException newMethodArgsInvalidValueException(
+ String methodName, Object... details) {
+ return new _TemplateModelException(methodName, "(...) arguments have invalid value: ", details);
+ }
+
+ static TemplateException newInstantiatingClassNotAllowedException(String className, Environment env) {
+ return new _MiscTemplateException(env,
+ "Instantiating ", className, " is not allowed in the template for security reasons.");
+ }
+
+ static _TemplateModelException newCantFormatUnknownTypeDateException(
+ Expression dateSourceExpr, UnknownDateTypeFormattingUnsupportedException cause) {
+ return new _TemplateModelException(cause, null, new _ErrorDescriptionBuilder(
+ _MessageUtil.UNKNOWN_DATE_TO_STRING_ERROR_MESSAGE)
+ .blame(dateSourceExpr)
+ .tips(_MessageUtil.UNKNOWN_DATE_TO_STRING_TIPS));
+ }
+
+ static TemplateException newCantFormatDateException(TemplateDateFormat format, Expression dataSrcExp,
+ TemplateValueFormatException e, boolean useTempModelExc) {
+ _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
+ "Failed to format date/time/datetime with format ", new _DelayedJQuote(format.getDescription()), ": ",
+ e.getMessage())
+ .blame(dataSrcExp);
+ return useTempModelExc
+ ? new _TemplateModelException(e, (Environment) null, desc)
+ : new _MiscTemplateException(e, (Environment) null, desc);
+ }
+
+ static TemplateException newCantFormatNumberException(TemplateNumberFormat format, Expression dataSrcExp,
+ TemplateValueFormatException e, boolean useTempModelExc) {
+ _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
+ "Failed to format number with format ", new _DelayedJQuote(format.getDescription()), ": ",
+ e.getMessage())
+ .blame(dataSrcExp);
+ return useTempModelExc
+ ? new _TemplateModelException(e, (Environment) null, desc)
+ : new _MiscTemplateException(e, (Environment) null, desc);
+ }
+
+ /**
+ * @return "a" or "an" or "a(n)" (or "" for empty string) for an FTL type name
+ */
+ static String getAOrAn(String s) {
+ if (s == null) return null;
+ if (s.length() == 0) return "";
+
+ char fc = Character.toLowerCase(s.charAt(0));
+ if (fc == 'a' || fc == 'e' || fc == 'i') {
+ return "an";
+ } else if (fc == 'h') {
+ String ls = s.toLowerCase();
+ if (ls.startsWith("has") || ls.startsWith("hi")) {
+ return "a";
+ } else if (ls.startsWith("ht")) {
+ return "an";
+ } else {
+ return "a(n)";
+ }
+ } else if (fc == 'u' || fc == 'o') {
+ return "a(n)";
+ } else {
+ char sc = (s.length() > 1) ? s.charAt(1) : '\0';
+ if (fc == 'x' && !(sc == 'a' || sc == 'e' || sc == 'i' || sc == 'a' || sc == 'o' || sc == 'u')) {
+ return "an";
+ } else {
+ return "a";
+ }
+ }
+ }
+
+}
[4/6] incubator-freemarker git commit: Added
TemplateModelUtils.getKeyValuePairIterator(TemplateHashModelEx) static
utility class,
which can be used to get a TemplateHashModelEx2.KeyValuePairIterator even for
a non-TemplateHashModelEx2 object. This simpl
Posted by dd...@apache.org.
Added TemplateModelUtils.getKeyValuePairIterator(TemplateHashModelEx) static utility class, which can be used to get a TemplateHashModelEx2.KeyValuePairIterator even for a non-TemplateHashModelEx2 object. This simplifies Java code that iterates through key-value pairs.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/59f2e7b8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/59f2e7b8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/59f2e7b8
Branch: refs/heads/2.3
Commit: 59f2e7b8c082b6405850fc2163b78fac3cbdd4dc
Parents: c533df5
Author: ddekany <dd...@apache.org>
Authored: Wed Feb 28 11:31:37 2018 +0100
Committer: ddekany <dd...@apache.org>
Committed: Wed Feb 28 11:31:37 2018 +0100
----------------------------------------------------------------------
.../java/freemarker/core/IteratorBlock.java | 13 +-
src/main/java/freemarker/core/_MessageUtil.java | 8 +-
.../template/utility/TemplateModelUtils.java | 90 +++++++++++
src/manual/en_US/book.xml | 12 +-
.../template/utility/TemplateModelUtilTest.java | 155 +++++++++++++++++++
5 files changed, 262 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/59f2e7b8/src/main/java/freemarker/core/IteratorBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/IteratorBlock.java b/src/main/java/freemarker/core/IteratorBlock.java
index 83c0b22..bbb6773 100644
--- a/src/main/java/freemarker/core/IteratorBlock.java
+++ b/src/main/java/freemarker/core/IteratorBlock.java
@@ -392,17 +392,8 @@ final class IteratorBlock extends TemplateElement {
listLoop: do {
loopVar = keysIter.next();
if (!(loopVar instanceof TemplateScalarModel)) {
- throw new NonStringException(env,
- new _ErrorDescriptionBuilder(
- "When listing key-value pairs of traditional hash "
- + "implementations, all keys must be strings, but one of them "
- + "was ",
- new _DelayedAOrAn(new _DelayedFTLTypeDescription(loopVar)), "."
- ).tip("The listed value's TemplateModel class was ",
- new _DelayedShortClassName(listedValue.getClass()),
- ", which doesn't implement ",
- new _DelayedShortClassName(TemplateHashModelEx2.class),
- ", which leads to this restriction."));
+ throw _MessageUtil.newKeyValuePairListingNonStringKeyExceptionMessage(
+ loopVar, (TemplateHashModelEx) listedValue);
}
loopVar2 = listedHash.get(((TemplateScalarModel) loopVar).getAsString());
hasNext = keysIter.hasNext();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/59f2e7b8/src/main/java/freemarker/core/_MessageUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/_MessageUtil.java b/src/main/java/freemarker/core/_MessageUtil.java
index db097db..42cfac7 100644
--- a/src/main/java/freemarker/core/_MessageUtil.java
+++ b/src/main/java/freemarker/core/_MessageUtil.java
@@ -322,10 +322,10 @@ public class _MessageUtil {
? new _TemplateModelException(e, (Environment) null, desc)
: new _MiscTemplateException(e, (Environment) null, desc);
}
-
- public static _ErrorDescriptionBuilder traditionalHashExKeyMustBeStringExceptionMessage(
+
+ public static TemplateModelException newKeyValuePairListingNonStringKeyExceptionMessage(
TemplateModel key, TemplateHashModelEx listedHashEx) {
- return new _ErrorDescriptionBuilder(
+ return new _TemplateModelException(new _ErrorDescriptionBuilder(
"When listing key-value pairs of traditional hash "
+ "implementations, all keys must be strings, but one of them "
+ "was ",
@@ -334,7 +334,7 @@ public class _MessageUtil {
new _DelayedShortClassName(listedHashEx.getClass()),
", which doesn't implement ",
new _DelayedShortClassName(TemplateHashModelEx2.class),
- ", which leads to this restriction.");
+ ", which leads to this restriction."));
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/59f2e7b8/src/main/java/freemarker/template/utility/TemplateModelUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/utility/TemplateModelUtils.java b/src/main/java/freemarker/template/utility/TemplateModelUtils.java
new file mode 100644
index 0000000..d33b6da
--- /dev/null
+++ b/src/main/java/freemarker/template/utility/TemplateModelUtils.java
@@ -0,0 +1,90 @@
+/*
+ * 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.template.utility;
+
+import freemarker.core._MessageUtil;
+import freemarker.template.TemplateHashModelEx;
+import freemarker.template.TemplateHashModelEx2;
+import freemarker.template.TemplateHashModelEx2.KeyValuePair;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateModelIterator;
+import freemarker.template.TemplateScalarModel;
+
+/**
+ * Static utility method related to {@link TemplateModel}-s that didn't fit elsewhere.
+ *
+ * @since 2.3.28
+ */
+public final class TemplateModelUtils {
+
+ // Private to prevent instantiation
+ private TemplateModelUtils() {
+ // no op.
+ }
+
+ /**
+ * {@link TemplateHashModelExKeyValuePairIterator} that even works for a non-{@link TemplateHashModelEx2}
+ * {@link TemplateHashModelEx}. This is used to simplify code that needs to iterate through the key-value pairs of
+ * {@link TemplateHashModelEx}-s, as with this you don't have to handle non-{@link TemplateHashModelEx2}-s
+ * separately. For non-{@link TemplateHashModelEx2} values the iteration will throw {@link TemplateModelException}
+ * if it reaches a key that's not a string ({@link TemplateScalarModel}).
+ */
+ public static final TemplateHashModelEx2.KeyValuePairIterator getKeyValuePairIterator(TemplateHashModelEx hash)
+ throws TemplateModelException {
+ return hash instanceof TemplateHashModelEx2 ? ((TemplateHashModelEx2) hash).keyValuePairIterator()
+ : new TemplateHashModelExKeyValuePairIterator(hash);
+ }
+
+ private static class TemplateHashModelExKeyValuePairIterator implements TemplateHashModelEx2.KeyValuePairIterator {
+
+ private final TemplateHashModelEx hash;
+ private final TemplateModelIterator keyIter;
+
+ private TemplateHashModelExKeyValuePairIterator(TemplateHashModelEx hash) throws TemplateModelException {
+ this.hash = hash;
+ keyIter = hash.keys().iterator();
+ }
+
+ public boolean hasNext() throws TemplateModelException {
+ return keyIter.hasNext();
+ }
+
+ public KeyValuePair next() throws TemplateModelException {
+ final TemplateModel key = keyIter.next();
+ if (!(key instanceof TemplateScalarModel)) {
+ throw _MessageUtil.newKeyValuePairListingNonStringKeyExceptionMessage(key, hash);
+ }
+
+ return new KeyValuePair() {
+
+ public TemplateModel getKey() throws TemplateModelException {
+ return key;
+ }
+
+ public TemplateModel getValue() throws TemplateModelException {
+ return hash.get(((TemplateScalarModel) key).getAsString());
+ }
+
+ };
+ }
+
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/59f2e7b8/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index b208ecd..56851f3 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -30,7 +30,7 @@
<titleabbrev>Manual</titleabbrev>
- <productname>Freemarker 2.3.27</productname>
+ <productname>Freemarker 2.3.28</productname>
</info>
<preface role="index.html" xml:id="preface">
@@ -27157,6 +27157,16 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting>
</listitem>
</itemizedlist>
</listitem>
+
+ <listitem>
+ <para>Added
+ <literal>TemplateModelUtils.getKeyValuePairIterator(TemplateHashModelEx)</literal>
+ static utility class, which can be used to get a
+ <literal>TemplateHashModelEx2.KeyValuePairIterator</literal>
+ even for a non-<literal>TemplateHashModelEx2</literal> object.
+ This simplifies Java code that iterates through key-value
+ pairs.</para>
+ </listitem>
</itemizedlist>
</section>
</section>
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/59f2e7b8/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java b/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
new file mode 100644
index 0000000..6179e17
--- /dev/null
+++ b/src/test/java/freemarker/template/utility/TemplateModelUtilTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.template.utility;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.DefaultMapAdapter;
+import freemarker.template.DefaultNonListCollectionAdapter;
+import freemarker.template.DefaultObjectWrapperBuilder;
+import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateHashModelEx;
+import freemarker.template.TemplateHashModelEx2.KeyValuePair;
+import freemarker.template.TemplateHashModelEx2.KeyValuePairIterator;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+import freemarker.template.TemplateScalarModel;
+import freemarker.test.TemplateTest;
+
+public class TemplateModelUtilTest extends TemplateTest {
+
+ @Test
+ public void testGetKeyValuePairIterator() throws Exception {
+ Map<Object, Object> map = new LinkedHashMap<Object, Object>();
+ TemplateHashModelEx thme = new TemplateHashModelExOnly(map);
+
+ assertetKeyValuePairIteratorResult("", thme);
+
+ map.put("k1", 11);
+ assertetKeyValuePairIteratorResult("str(k1): num(11)", thme);
+
+ map.put("k2", "v2");
+ assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): str(v2)", thme);
+
+ map.put("k2", null);
+ assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): null", thme);
+
+ map.put(3, 33);
+ try {
+ assertetKeyValuePairIteratorResult("fails anyway...", thme);
+ fail();
+ } catch (TemplateModelException e) {
+ assertThat(e.getMessage(),
+ allOf(containsString("keys must be"), containsString("string"), containsString("number")));
+ }
+ map.remove(3);
+
+ map.put(null, 44);
+ try {
+ assertetKeyValuePairIteratorResult("fails anyway...", thme);
+ fail();
+ } catch (TemplateModelException e) {
+ assertThat(e.getMessage(),
+ allOf(containsString("keys must be"), containsString("string"), containsString("Null")));
+ }
+ }
+
+ @Test
+ public void testGetKeyValuePairIteratorWithEx2() throws Exception {
+ Map<Object, Object> map = new LinkedHashMap<Object, Object>();
+ TemplateHashModelEx thme = DefaultMapAdapter.adapt(
+ map, (ObjectWrapperWithAPISupport) getConfiguration().getObjectWrapper());
+
+ assertetKeyValuePairIteratorResult("", thme);
+
+ map.put("k1", 11);
+ map.put("k2", "v2");
+ map.put("k2", null);
+ map.put(3, 33);
+ map.put(null, 44);
+ assertetKeyValuePairIteratorResult("str(k1): num(11), str(k2): null, num(3): num(33), null: num(44)", thme);
+ }
+
+ private void assertetKeyValuePairIteratorResult(String expected, TemplateHashModelEx thme)
+ throws TemplateModelException {
+ StringBuilder sb = new StringBuilder();
+ KeyValuePairIterator kvpi = TemplateModelUtils.getKeyValuePairIterator(thme);
+ while (kvpi.hasNext()) {
+ KeyValuePair kvp = kvpi.next();
+ if (sb.length() != 0) {
+ sb.append(", ");
+ }
+ sb.append(toAssertionString(kvp.getKey())).append(": ").append(toAssertionString(kvp.getValue()));
+ }
+ }
+
+ private String toAssertionString(TemplateModel model) throws TemplateModelException {
+ if (model instanceof TemplateNumberModel) {
+ return "num(" + ((TemplateNumberModel) model).getAsNumber() + ")";
+ } else if (model instanceof TemplateScalarModel) {
+ return "str(" + ((TemplateScalarModel) model).getAsString() + ")";
+ } else if (model == null) {
+ return "null";
+ }
+
+ throw new IllegalArgumentException("Type unsupported by test: " + model.getClass().getName());
+ }
+
+ private static class TemplateHashModelExOnly implements TemplateHashModelEx {
+
+ private final Map<?, ?> map;
+ private final ObjectWrapperWithAPISupport objectWrapper;
+
+ public TemplateHashModelExOnly(Map<?, ?> map) {
+ this.map = map;
+ objectWrapper = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27).build();
+ }
+
+ public TemplateModel get(String key) throws TemplateModelException {
+ return objectWrapper.wrap(map.get(key));
+ }
+
+ public boolean isEmpty() throws TemplateModelException {
+ return map.isEmpty();
+ }
+
+ public int size() throws TemplateModelException {
+ return 2;
+ }
+
+ public TemplateCollectionModel keys() throws TemplateModelException {
+ return DefaultNonListCollectionAdapter.adapt(map.keySet(), objectWrapper);
+ }
+
+ public TemplateCollectionModel values() throws TemplateModelException {
+ return DefaultNonListCollectionAdapter.adapt(map.values(), objectWrapper);
+ }
+
+ }
+
+}