Repository: incubator-freemarker Updated Branches: refs/heads/3 8c6b4ec41 -> 888ebe114
FREEMARKER-65: Added org.apache.freemarker.core.util.CallableUtils to help implementing function and directives in Java. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/888ebe11 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/888ebe11 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/888ebe11 Branch: refs/heads/3 Commit: 888ebe1140d30acae6378d5235202fa755e4a8a6 Parents: 8c6b4ec Author: ddekany <ddek...@apache.org> Authored: Sun Aug 20 23:12:19 2017 +0200 Committer: ddekany <ddek...@apache.org> Committed: Sun Aug 20 23:24:49 2017 +0200 ---------------------------------------------------------------------- FM3-CHANGE-LOG.txt | 1 + .../core/BuiltInsForMultipleTypes.java | 3 +- .../core/BuiltInsForStringsBasic.java | 5 +- .../core/model/TemplateCallableModel.java | 4 + .../core/model/TemplateDirectiveModel.java | 3 + .../core/model/TemplateFunctionModel.java | 3 + .../core/model/impl/ResourceBundleModel.java | 6 +- .../freemarker/core/util/CallableUtils.java | 528 +++++++++++++++++-- .../test/templateutil/AssertDirective.java | 14 +- .../templateutil/AssertEqualsDirective.java | 20 +- .../test/templateutil/AssertFailsDirective.java | 59 +-- .../templateutil/BadParameterTypeException.java | 60 --- .../MissingRequiredParameterException.java | 51 -- .../test/templateutil/ParameterException.java | 54 -- .../UnsupportedParameterException.java | 50 -- 15 files changed, 512 insertions(+), 349 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/FM3-CHANGE-LOG.txt ---------------------------------------------------------------------- diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt index 8e08099..033fcc6 100644 --- a/FM3-CHANGE-LOG.txt +++ b/FM3-CHANGE-LOG.txt @@ -377,6 +377,7 @@ Core / Models and Object wrapping the common interface bith for wrapped Java methods and functions defined in the templates, or on any other ways. `OverloadedMethodsModel` and `SimpleMethodModel` were renamed to `OverloadJavaMethodModel` and `SimpleJavaMethodModel`, which of course extend `TemplateFunctionModel`, but allow inocations without `Environment` parameter. +- `org.apache.freemarker.core.util.CallableUtils` was added to help implementing function and directives in Java. - `TemplateModelException` was removed, replaced with `TemplateException` on all places, except for `ObjectWrapper.wrap(Object)` and `wrapAsAPI(Object)`, which now throws `ObjectWrappingException` instead (that extends `TemplateException`). http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java index 6335777..159c284 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java @@ -475,7 +475,8 @@ class BuiltInsForMultipleTypes { TemplateModel result = args[argIdx]; if (!(result instanceof TemplateScalarModel)) { // Cause usual type exception - CallableUtils.castArgumentValueToString(result, argIdx, this, true, false); + CallableUtils.castArgumentValueToString( + result, argIdx, false, null, this, true); } return result; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java index 1eaeb2d..91eac72 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java @@ -705,9 +705,10 @@ class BuiltInsForStringsBasic { throw newIndexGreaterThanLengthException(1, endIdx, len); } if (beginIdx > endIdx) { - throw newGenericExecuteException(this, + throw newGenericExecuteException( "The begin index argument, " + beginIdx - + ", shouldn't be greater than the end index argument, " + endIdx + "."); + + ", shouldn't be greater than the end index argument, " + endIdx + ".", + this); } return new SimpleScalar(s.substring(beginIdx, endIdx)); } else { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCallableModel.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCallableModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCallableModel.java index caa612a..d287757 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCallableModel.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateCallableModel.java @@ -19,9 +19,13 @@ package org.apache.freemarker.core.model; +import org.apache.freemarker.core.util.CallableUtils; + /** * Super interface (marker interface) of {@link TemplateFunctionModel} and {@link TemplateDirectiveModel}; don' extended * (or implement) it yourself! + * <p> + * You can find utilities for implementing {@link TemplateCallableModel}-s in {@link CallableUtils}. */ public interface TemplateCallableModel extends TemplateModel { // http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java index be06cba..bfdc118 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateDirectiveModel.java @@ -8,6 +8,7 @@ import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.NonTemplateCallPlace; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.impl.JavaMethodModel; +import org.apache.freemarker.core.util.CallableUtils; /** * A {@link TemplateCallableModel} that progressively writes it result into the {@code out} object, instead of @@ -21,6 +22,8 @@ import org.apache.freemarker.core.model.impl.JavaMethodModel; * <p> * Example usage in a template: {@code <@my.menu style="foo" expand=true>...</@my.menu>}, * {@code <@my.menuItem "Some title" icon="some.jpg" />}. + * <p> + * You can find utilities for implementing {@link TemplateDirectiveModel}-s in {@link CallableUtils}. */ public interface TemplateDirectiveModel extends TemplateCallableModel { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateFunctionModel.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateFunctionModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateFunctionModel.java index 70824ec..3dcd10a 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateFunctionModel.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateFunctionModel.java @@ -6,6 +6,7 @@ import org.apache.freemarker.core.CallPlace; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.impl.JavaMethodModel; +import org.apache.freemarker.core.util.CallableUtils; /** * A {@link TemplateCallableModel}, which returns its result as a {@link TemplateModel} at the end of its execution. @@ -16,6 +17,8 @@ import org.apache.freemarker.core.model.impl.JavaMethodModel; * <p> * Example usage in templates: {@code < a href="${my.toProductURL(product.id)}">}, * {@code <#list my.groupByFirstLetter(products, property="name") as productGroup>} + * <p> + * You can find utilities for implementing {@link TemplateFunctionModel}-s in {@link CallableUtils}. */ public interface TemplateFunctionModel extends TemplateCallableModel { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java index aaf3702..037ff15 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java @@ -125,10 +125,10 @@ public class ResourceBundleModel extends BeanModel implements TemplateFunctionMo // Invoke format return new BeanAndStringModel(format(key, params), wrapper); } catch (MissingResourceException e) { - throw CallableUtils.newGenericExecuteException(this, "No such key: " + key, e); + throw CallableUtils.newGenericExecuteException("No such key: " + key, this, e); } catch (Exception e) { - throw CallableUtils.newGenericExecuteException(this, - "Failed to get or format message; see cause exception", e); + throw CallableUtils.newGenericExecuteException("Failed to get or format message; see cause exception", this, + e); } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-core/src/main/java/org/apache/freemarker/core/util/CallableUtils.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/CallableUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/CallableUtils.java index 4f6dc5d..796d082 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/CallableUtils.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/CallableUtils.java @@ -35,6 +35,7 @@ import org.apache.freemarker.core._ErrorDescriptionBuilder; import org.apache.freemarker.core._EvalUtils; import org.apache.freemarker.core._UnexpectedTypeErrorExplainerTemplateModel; import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.TemplateBooleanModel; import org.apache.freemarker.core.model.TemplateCallableModel; import org.apache.freemarker.core.model.TemplateDirectiveModel; import org.apache.freemarker.core.model.TemplateFunctionModel; @@ -44,51 +45,79 @@ import org.apache.freemarker.core.model.TemplateScalarModel; import org.apache.freemarker.core.model.TemplateSequenceModel; /** - * For internal use only; don't depend on this, there's no backward compatibility guarantee at all! + * Utilities for implementing and calling {@link TemplateCallableModel}-s (such as {@link TemplateDirectiveModel}-s + * and {@link TemplateFunctionModel}-s). */ public final class CallableUtils { + /** Empty {@link TemplateModel} array, useful to avoid array creation for a 0 length argument list. */ public static final TemplateModel[] EMPTY_TEMPLATE_MODEL_ARRAY = new TemplateModel[0]; private CallableUtils() { // } - /** Convenience method for calling {@link #newGenericExecuteException(TemplateCallableModel, boolean, String)}. */ + /** + * Convenience method for calling + * {@link #newGenericExecuteException(String, TemplateCallableModel, boolean, Throwable)} + */ public static TemplateException newGenericExecuteException( - TemplateFunctionModel callable, String errorDescription) { - return newGenericExecuteException(callable, true, errorDescription); + String errorDescription, TemplateFunctionModel callable) { + return newGenericExecuteException(errorDescription, callable, true); } - /** Convenience method for calling {@link #newGenericExecuteException(TemplateCallableModel, boolean, String)}. */ + /** + * Convenience method for calling + * {@link #newGenericExecuteException(String, TemplateCallableModel, boolean, Throwable)} + */ public static TemplateException newGenericExecuteException( - TemplateDirectiveModel callable, String errorDescription) { - return newGenericExecuteException(callable, false, errorDescription); + String errorDescription, TemplateDirectiveModel callable) { + return newGenericExecuteException(errorDescription, callable, false); } + /** + * Convenience method for calling + * {@link #newGenericExecuteException(String, TemplateCallableModel, boolean, Throwable)} + */ public static TemplateException newGenericExecuteException( - TemplateCallableModel callable, boolean calledAsFunction, String errorDescription) { - return newGenericExecuteException(callable, calledAsFunction, errorDescription, null); + String errorDescription, TemplateCallableModel callable, boolean calledAsFunction) { + return newGenericExecuteException(errorDescription, callable, calledAsFunction, null); } - /** Convenience method for calling {@link #newGenericExecuteException(TemplateCallableModel, boolean, String)}. */ + /** + * Convenience method for calling + * {@link #newGenericExecuteException(String, TemplateCallableModel, boolean, Throwable)} + */ public static TemplateException newGenericExecuteException( - TemplateFunctionModel callable, String errorDescription, Throwable cause) { - return newGenericExecuteException(callable, true, errorDescription, cause); + String errorDescription, TemplateFunctionModel callable, Throwable cause) { + return newGenericExecuteException(errorDescription, callable, true, cause); } - /** Convenience method for calling {@link #newGenericExecuteException(TemplateCallableModel, boolean, String)}. */ + /** + * Convenience method for calling + * {@link #newGenericExecuteException(String, TemplateCallableModel, boolean, Throwable)} + */ public static TemplateException newGenericExecuteException( - TemplateDirectiveModel callable, String errorDescription, Throwable cause) { - return newGenericExecuteException(callable, false, errorDescription, cause); + String errorDescription, TemplateDirectiveModel callable, Throwable cause) { + return newGenericExecuteException(errorDescription, callable, false, cause); } /** - * @param errorDescription Complete sentence describing the problem. This will be after - * {@code "When calling xxx: "}. + * Creates an exception related to the execution of a {@link TemplateCallableModel}, for which there's no more + * specific method in {@link CallableUtils}. + * + * @param errorDescription + * Complete sentence describing the problem. This will be shown after {@code "When calling Foo: "}. + * @param callable + * The {@link TemplateCallableModel} whose execution was failed.; required for printing proper error + * message. + * @param calledAsFunction + * Tells if the {@code callable} was called as function (as opposed to called as a directive), which is + * needed for proper error messages. This information is needed because a {@link TemplateCallableModel} + * might implements both {@link TemplateFunctionModel} and {@link TemplateDirectiveModel}. */ public static TemplateException newGenericExecuteException( - TemplateCallableModel callable, boolean calledAsFunction, String errorDescription, + String errorDescription, TemplateCallableModel callable, boolean calledAsFunction, Throwable cause) { return new TemplateException(cause, _CallableUtils.getMessagePartWhenCallingSomethingColon(callable, calledAsFunction), @@ -119,6 +148,7 @@ public final class CallableUtils { return _newArgumentValueException(argIdx, problemDescription, callable, calledAsFunction, null); } + /** Don't use it; used internally by FreeMarker, may changes anytime without notice. */ // TODO [FM3] How to expose tips API? public static TemplateException _newArgumentValueException( int argIdx, String problemDescription, @@ -214,6 +244,7 @@ public final class CallableUtils { return _newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction, null); } + /** Don't use it; used internally by FreeMarker, may changes anytime without notice. */ // TODO [FM3] How to expose tips API? public static TemplateException _newNullOrOmittedArgumentException(int argIdx, TemplateCallableModel callable, boolean calledAsFunction, Object[] tips) { @@ -310,72 +341,85 @@ public final class CallableUtils { /** * Convenience method to call - * {@link #castArgumentValueToString(TemplateModel, int, TemplateCallableModel, boolean, boolean) - * castArgumentValueToString(args[argIndex], argIndex, callable, true, false)}. + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, false, null, callable, true)}. */ public static String getStringArgument( TemplateModel[] args, int argIndex, TemplateFunctionModel callable) throws TemplateException { - return castArgumentValueToString(args[argIndex], argIndex, callable, true, false); + return castArgumentValueToString(args[argIndex], argIndex, false, null, callable, true); } /** * Convenience method to call - * {@link #castArgumentValueToString(TemplateModel, int, TemplateCallableModel, boolean, boolean) - * castArgumentValueToString(args[argIndex], argIndex, callable, false, false)}. + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, false, null, callable, false)}. */ public static String getStringArgument( TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) throws TemplateException { - return castArgumentValueToString(args[argIndex], argIndex, callable, false, false); + return castArgumentValueToString(args[argIndex], argIndex, false, null, callable, false); } /** * Convenience method to call - * {@link #castArgumentValueToString(TemplateModel, int, TemplateCallableModel, boolean, boolean) - * castArgumentValueToString(args[argIndex], argIndex, callable, true, true)}. + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, true, null, callable, true)}. */ public static String getOptionalStringArgument( TemplateModel[] args, int argIndex, TemplateFunctionModel callable) throws TemplateException { - return castArgumentValueToString(args[argIndex], argIndex, callable, true, true); + return castArgumentValueToString(args[argIndex], argIndex, true, null, callable, true); } /** * Convenience method to call - * {@link #castArgumentValueToString(TemplateModel, int, TemplateCallableModel, boolean, boolean) - * castArgumentValueToString(args[argIndex], argIndex, callable, false, true)}. + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, true, null, callable, false)}. */ public static String getOptionalStringArgument( TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) throws TemplateException { - return castArgumentValueToString(args[argIndex], argIndex, callable, false, true); + return castArgumentValueToString(args[argIndex], argIndex, true, null, callable, false); } /** - * Checks if the argument value is a string; it does NOT check if {@code args} is big enough. - * - * @param calledAsFunction - * If {@code callable} was called as function (as opposed to called as a directive) - * @param optional - * If we allow a {@code null} return value - * - * @return Null {@code null} if the argument was omitted or {@code null} - * - * @throws TemplateException - * If the argument is not of the proper type or is non-optional yet {@code null}. The error message - * describes the problem in detail. + * Convenience method to call + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, true, defaultValue, callable, true)}. + */ + public static String getOptionalStringArgument( + TemplateModel[] args, int argIndex, String defaultValue, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToString(args[argIndex], argIndex, true, defaultValue, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToString(TemplateModel, int, boolean, String, TemplateCallableModel, boolean) + * castArgumentValueToString(args[argIndex], argIndex, true, defaultValue, callable, false)}. + */ + public static String getOptionalStringArgument( + TemplateModel[] args, int argIndex, String defaultValue, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToString(args[argIndex], argIndex, true, defaultValue, callable, false); + } + + /** + * See {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, + * boolean)}; this does the same, but with {@link TemplateScalarModel} as {@code type}, and with {@link String} + * return value. */ public static String castArgumentValueToString( - TemplateModel argValue, int argIdx, TemplateCallableModel callable, - boolean calledAsFunction, boolean optional) + TemplateModel argValue, int argIdx, boolean optional, String defaultValue, + TemplateCallableModel callable, boolean calledAsFunction) throws TemplateException { if (argValue instanceof TemplateScalarModel) { return _EvalUtils.modelToString((TemplateScalarModel) argValue, null); } if (argValue == null) { if (optional) { - return null; + return defaultValue; } throw newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction); } @@ -383,41 +427,88 @@ public final class CallableUtils { } // Number arg: - + + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, false, null, callable, true)}. + */ public static Number getNumberArgument( TemplateModel[] args, int argIndex, TemplateFunctionModel callable) throws TemplateException { - return castArgumentValueToNumber(args[argIndex], argIndex, callable, true, false); + return castArgumentValueToNumber(args[argIndex], argIndex, false, null, callable, true); } + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, false, null, callable, false)}. + */ public static Number getNumberArgument( TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) throws TemplateException { - return castArgumentValueToNumber(args[argIndex], argIndex, callable, false, false); + return castArgumentValueToNumber(args[argIndex], argIndex, false, null, callable, false); } + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, true, null, callable, true)}. + */ public static Number getOptionalNumberArgument( TemplateModel[] args, int argIndex, TemplateFunctionModel callable) throws TemplateException { - return castArgumentValueToNumber(args[argIndex], argIndex, callable, true, true); + return castArgumentValueToNumber(args[argIndex], argIndex, true, null, callable, true); } + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, true, null, callable, false)}. + */ public static Number getOptionalNumberArgument( TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) throws TemplateException { - return castArgumentValueToNumber(args[argIndex], argIndex, callable, false, true); + return castArgumentValueToNumber(args[argIndex], argIndex, true, null, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, true, defaultValue, callable, true)}. + */ + public static Number getOptionalNumberArgument( + TemplateModel[] args, int argIndex, Number defaultValue, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToNumber(args[argIndex], argIndex, true, defaultValue, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToNumber(TemplateModel, int, boolean, Number, TemplateCallableModel, boolean) + * castArgumentValueToNumber(args[argIndex], argIndex, true, defaultValue, callable, false)}. + */ + public static Number getOptionalNumberArgument( + TemplateModel[] args, int argIndex, Number defaultValue, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToNumber(args[argIndex], argIndex, true, defaultValue, callable, false); } + /** + * See {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, + * boolean)}; this does the same, but with {@link TemplateNumberModel} as {@code type}, and with {@link Number} + * return value. + */ public static Number castArgumentValueToNumber( - TemplateModel argValue, int argIdx, TemplateCallableModel callable, - boolean calledAsFunction, boolean optional) + TemplateModel argValue, int argIdx, boolean optional, Number defaultValue, TemplateCallableModel callable, + boolean calledAsFunction) throws TemplateException { if (argValue instanceof TemplateNumberModel) { return _EvalUtils.modelToNumber((TemplateNumberModel) argValue, null); } if (argValue == null) { if (optional) { - return null; + return defaultValue; } throw newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction); } @@ -426,8 +517,319 @@ public final class CallableUtils { calledAsFunction); } - // TODO boolean, etc. + // int arg: + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, false, null, callable, true)}. + */ + public static int getIntArgument( + TemplateModel[] args, int argIndex, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, false, 0, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, false, null, callable, false)}. + */ + public static int getIntArgument( + TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, false, 0, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, true, null, callable, true)}. + */ + public static int getOptionalIntArgument( + TemplateModel[] args, int argIndex, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, true, 0, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, true, null, callable, false)}. + */ + public static int getOptionalIntArgument( + TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, true, 0, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, true, defaultValue, callable, true)}. + */ + public static int getOptionalIntArgument( + TemplateModel[] args, int argIndex, int defaultValue, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, true, defaultValue, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToInt(TemplateModel, int, boolean, int, TemplateCallableModel, boolean) + * castArgumentValueToInt(args[argIndex], argIndex, true, defaultValue, callable, false)}. + */ + public static int getOptionalIntArgument( + TemplateModel[] args, int argIndex, int defaultValue, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToInt(args[argIndex], argIndex, true, defaultValue, callable, false); + } + + /** + * See {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, + * boolean)}; this does the same, but with {@link TemplateNumberModel} as {@code type} and with the restriction that + * the number must be convertable to {@code int} losselessly, and with {@link int} return value. + */ + public static int castArgumentValueToInt( + TemplateModel argValue, int argIdx, boolean optional, int defaultValue, TemplateCallableModel callable, + boolean calledAsFunction) + throws TemplateException { + if (argValue instanceof TemplateNumberModel) { + Number nm = _EvalUtils.modelToNumber((TemplateNumberModel) argValue, null); + try { + return _NumberUtils.toIntExact(nm); + } catch (ArithmeticException e) { + throw newArgumentValueException(argIdx, "must be an integer (that fits into 32 bits), but " + + nm + " (class: " + _ClassUtils.getShortClassName(nm.getClass()) + + ") is not a such number.", + callable, + calledAsFunction); + } + } + if (argValue == null) { + if (optional) { + return defaultValue; + } + throw newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction); + } + throw newArgumentValueTypeException( + argValue, argIdx, new Class[] { TemplateNumberModel.class }, "number (int)", callable, + calledAsFunction); + } + + // Boolean arg: + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, false, null, callable, true)}. + */ + public static boolean getBooleanArgument( + TemplateModel[] args, int argIndex, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, false, null, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, false, null, callable, false)}. + */ + public static boolean getBooleanArgument( + TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, false, null, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, true, null, callable, true)}. + */ + public static Boolean getOptionalBooleanArgument( + TemplateModel[] args, int argIndex, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, true, null, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, true, null, callable, false)}. + */ + public static Boolean getOptionalBooleanArgument( + TemplateModel[] args, int argIndex, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, true, null, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, true, defaultValue, callable, true)}. + */ + public static Boolean getOptionalBooleanArgument( + TemplateModel[] args, int argIndex, TemplateFunctionModel callable, Boolean defaultValue) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, true, defaultValue, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValueToBoolean(TemplateModel, int, boolean, Boolean, TemplateCallableModel, boolean) + * castArgumentValueToBoolean(args[argIndex], argIndex, true, defaultValue, callable, false)}. + */ + public static Boolean getOptionalBooleanArgument( + TemplateModel[] args, int argIndex, TemplateDirectiveModel callable, Boolean defaultValue) + throws TemplateException { + return castArgumentValueToBoolean(args[argIndex], argIndex, true, defaultValue, callable, false); + } + + /** + * See {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, + * boolean)}; this does the same, but with {@link TemplateBooleanModel} as {@code type}, and with {@link Boolean} + * return value. + */ + public static Boolean castArgumentValueToBoolean( + TemplateModel argValue, int argIdx, boolean optional, Boolean defaultValue, TemplateCallableModel callable, + boolean calledAsFunction) + throws TemplateException { + if (argValue instanceof TemplateBooleanModel) { + return ((TemplateBooleanModel) argValue).getAsBoolean(); + } + if (argValue == null) { + if (optional) { + return defaultValue; + } + throw newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction); + } + throw newArgumentValueTypeException( + argValue, argIdx, TemplateBooleanModel.class, callable, + calledAsFunction); + } + + // Other type of arg: + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, true, false, null)}. + */ + public static <T extends TemplateModel> T getArgument( + TemplateModel[] args, int argIndex, Class<T> type, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, false, null, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, false, false, null)}. + */ + public static <T extends TemplateModel> T getArgument( + TemplateModel[] args, int argIndex, Class<T> type, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, false, null, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, true, true, null)}. + */ + public static <T extends TemplateModel> T getOptionalArgument( + TemplateModel[] args, int argIndex, Class<T> type, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, true, null, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, true, true, null)}. + */ + public static <T extends TemplateModel> T getOptionalArgument( + TemplateModel[] args, int argIndex, Class<T> type, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, true, null, callable, false); + } + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, true, true, null)}. + */ + public static <T extends TemplateModel> T getOptionalArgument( + TemplateModel[] args, int argIndex, Class<T> type, T defaultValue, TemplateFunctionModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, true, defaultValue, callable, true); + } + + /** + * Convenience method to call + * {@link #castArgumentValue(TemplateModel, int, Class, boolean, TemplateModel, TemplateCallableModel, boolean)} + * castArgumentValueToSequence(args[argIndex], argIndex, callable, true, true, null)}. + */ + public static <T extends TemplateModel> T getOptionalArgument( + TemplateModel[] args, int argIndex, Class<T> type, T defaultValue, TemplateDirectiveModel callable) + throws TemplateException { + return castArgumentValue(args[argIndex], argIndex, type, true, defaultValue, callable, false); + } + + /** + * Checks if the argument value is of the proper type, also, if it's {@code null}/omitted, in which case it can + * throw an exception or return a default value. + * <p> + * The point of this method is not only to decrease the boiler plate needed for these common checks, but also to + * standardize the error message content. If the checks themselves don't fit your needs, you should still use {@link + * #newArgumentValueTypeException(TemplateModel, int, Class, TemplateCallableModel, boolean)} and its overloads, + * also {@link #newNullOrOmittedArgumentException(int, TemplateCallableModel, boolean)} and its overloads to + * generate similar error messages. + * + * @param argIdx + * The index in the {@code args} array (assumed to be a valid index. This is information is needed for + * proper error messages. + * @param type + * The expected class of the argument (usually a {@link TemplateModel} subinterface). {@code null} if + * there are no type restrictions. + * @param optional + * If we allow the parameter to be {@code null} or omitted. + * @param defaultValue + * The value to return if the parameter was {@code null} or omitted. + * @param callable + * The {@link TemplateCallableModel} whose argument we cast; required for printing proper error message. + * @param calledAsFunction + * Tells if the {@code callable} was called as function (as opposed to called as a directive). This + * information is needed because a {@link TemplateCallableModel} might implements both {@link + * TemplateFunctionModel} and {@link TemplateDirectiveModel}, in which case this method couldn't tell if the + * argument of which we are casting. + * + * @return The argument value of the proper type. + * + * @throws TemplateException + * If the argument is not of the proper type or is non-optional yet {@code null}/omitted. The error message + * describes the problem in detail, and is meant to be shown for the template author. + */ + public static <T extends TemplateModel> T castArgumentValue( + TemplateModel argValue, int argIdx, Class<T> type, + boolean optional, T defaultValue, TemplateCallableModel callable, + boolean calledAsFunction) + throws TemplateException { + if (argValue == null) { + if (optional) { + return defaultValue; + } + throw newNullOrOmittedArgumentException(argIdx, callable, calledAsFunction); + } + if (type == null || type.isInstance(argValue)) { + return (T) argValue; + } + throw newArgumentValueTypeException( + argValue, argIdx, type, callable, + calledAsFunction); + } + // Argument count /** Convenience method for calling {@link #checkArgumentCount(int, int, int, TemplateCallableModel, boolean)}. */ @@ -461,8 +863,22 @@ public final class CallableUtils { } /** - * Useful when the {@link ArgumentArrayLayout} is {@code null} and so the argument array length is not fixed, - * to check if the number of arguments is in the given range. + * Useful when the {@link ArgumentArrayLayout} is {@code null} and so the argument array length is not fixed, to + * check if the number of arguments is in the given range. + * + * @param argCnt + * The actual length of the argument array + * @param minCnt + * The minimum expected number of arguments + * @param maxCnt + * The maximum expected number of arguments. Should be equal to or greater than {@code minCnt} + * @param callable + * The {@link TemplateCallableModel} whose argument we cast; required for printing proper error message. + * @param calledAsFunction + * Tells if the {@code callable} was called as function (as opposed to called as a directive). This + * information is needed because a {@link TemplateCallableModel} might implements both {@link + * TemplateFunctionModel} and {@link TemplateDirectiveModel}, in which case this method couldn't tell if the + * argument of which we are casting. */ public static void checkArgumentCount(int argCnt, int minCnt, int maxCnt, TemplateCallableModel callable, boolean calledAsFunction) throws TemplateException { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java index d833c13..caccdc6 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertDirective.java @@ -26,10 +26,9 @@ import org.apache.freemarker.core.CallPlace; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.ArgumentArrayLayout; -import org.apache.freemarker.core.model.TemplateBooleanModel; import org.apache.freemarker.core.model.TemplateDirectiveModel; import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.util.TemplateLanguageUtils; +import org.apache.freemarker.core.util.CallableUtils; public class AssertDirective implements TemplateDirectiveModel { public static AssertDirective INSTANCE = new AssertDirective(); @@ -39,16 +38,7 @@ public class AssertDirective implements TemplateDirectiveModel { @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - TemplateModel test = args[0]; - if (test == null) { - throw new MissingRequiredParameterException("test", env); - } - if (!(test instanceof TemplateBooleanModel)) { - throw new AssertationFailedInTemplateException("Assertion failed:\n" - + "The value had to be boolean, but it was of type" + TemplateLanguageUtils.getTypeDescription(test), - env); - } - if (!((TemplateBooleanModel) test).getAsBoolean()) { + if (!CallableUtils.getBooleanArgument(args, 0, this)) { throw new AssertationFailedInTemplateException("Assertion failed:\n" + "the value was false.", env); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java index a894a7d..923ced8 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertEqualsDirective.java @@ -32,6 +32,7 @@ import org.apache.freemarker.core.model.TemplateDirectiveModel; import org.apache.freemarker.core.model.TemplateModel; import org.apache.freemarker.core.model.TemplateNumberModel; import org.apache.freemarker.core.model.TemplateScalarModel; +import org.apache.freemarker.core.util.CallableUtils; import org.apache.freemarker.core.util.StringToIndexMap; import org.apache.freemarker.core.util._StringUtils; @@ -42,12 +43,9 @@ public class AssertEqualsDirective implements TemplateDirectiveModel { private static final int ACTUAL_ARG_IDX = 0; private static final int EXPECTED_ARG_IDX = 1; - private static final String ACTUAL_ARG_NAME = "actual"; - private static final String EXPECTED_ARG_NAME = "expected"; - private static final StringToIndexMap ARG_NAME_TO_IDX = StringToIndexMap.of( - ACTUAL_ARG_NAME, ACTUAL_ARG_IDX, - EXPECTED_ARG_NAME, EXPECTED_ARG_IDX); + "actual", ACTUAL_ARG_IDX, + "expected", EXPECTED_ARG_IDX); private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create( 0, false, @@ -58,16 +56,8 @@ public class AssertEqualsDirective implements TemplateDirectiveModel { @Override public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - TemplateModel actual = args[ACTUAL_ARG_IDX]; - if (actual == null) { - throw new MissingRequiredParameterException(ACTUAL_ARG_NAME, env); - } - - TemplateModel expected = args[EXPECTED_ARG_IDX]; - if (expected == null) { - throw new MissingRequiredParameterException(EXPECTED_ARG_NAME, env); - } - + TemplateModel actual = CallableUtils.getArgument(args, ACTUAL_ARG_IDX, null, this); + TemplateModel expected = CallableUtils.getArgument(args, ACTUAL_ARG_IDX, null, this); if (!env.applyEqualsOperatorLenient(actual, expected)) { throw new AssertationFailedInTemplateException("Assertion failed:\n" + "Expected: " + tryUnwrap(expected) + "\n" http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java index e315ef6..9e82895 100644 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java +++ b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/AssertFailsDirective.java @@ -29,8 +29,7 @@ import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.ArgumentArrayLayout; import org.apache.freemarker.core.model.TemplateDirectiveModel; import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateNumberModel; -import org.apache.freemarker.core.model.TemplateScalarModel; +import org.apache.freemarker.core.util.CallableUtils; import org.apache.freemarker.core.util.StringToIndexMap; import org.apache.freemarker.core.util._NullWriter; import org.apache.freemarker.core.util._StringUtils; @@ -44,16 +43,11 @@ public class AssertFailsDirective implements TemplateDirectiveModel { private static final int EXCEPTION_ARG_IDX = 2; private static final int CAUSE_NESTING_LEVEL_ARG_IDX = 3; - private static final String MESSAGE_ARG_NAME = "message"; - private static final String MESSAGE_REGEXP_ARG_NAME = "messageRegexp"; - private static final String EXCEPTION_ARG_NAME = "exception"; - private static final String CAUSE_NESTING_LEVEL_ARG_NAME = "causeNestingLevel"; - private static final StringToIndexMap ARG_NAME_TO_IDX = StringToIndexMap.of( - MESSAGE_ARG_NAME, MESSAGE_ARG_IDX, - MESSAGE_REGEXP_ARG_NAME, MESSAGE_REGEXP_ARG_IDX, - EXCEPTION_ARG_NAME, EXCEPTION_ARG_IDX, - CAUSE_NESTING_LEVEL_ARG_NAME, CAUSE_NESTING_LEVEL_ARG_IDX); + "message", MESSAGE_ARG_IDX, + "messageRegexp", MESSAGE_REGEXP_ARG_IDX, + "exception", EXCEPTION_ARG_IDX, + "causeNestingLevel", CAUSE_NESTING_LEVEL_ARG_IDX); private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create( 0, false, @@ -64,10 +58,15 @@ public class AssertFailsDirective implements TemplateDirectiveModel { public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) throws TemplateException, IOException { - String message = getAsString(args[MESSAGE_ARG_IDX], MESSAGE_ARG_NAME, env); - Pattern messageRegexp = getAsPattern(args[MESSAGE_REGEXP_ARG_IDX], MESSAGE_REGEXP_ARG_NAME, env); - String exception = getAsString(args[EXCEPTION_ARG_IDX], EXCEPTION_ARG_NAME, env); - int causeNestingLevel = getAsInt(args[CAUSE_NESTING_LEVEL_ARG_IDX], 0, CAUSE_NESTING_LEVEL_ARG_NAME, env); + String message = CallableUtils.getOptionalStringArgument(args, MESSAGE_ARG_IDX, this); + Pattern messageRegexp; + { + String s = CallableUtils.getOptionalStringArgument(args, MESSAGE_REGEXP_ARG_IDX, this); + messageRegexp = s != null ? Pattern.compile(s, Pattern.CASE_INSENSITIVE) : null; + } + String exception = CallableUtils.getOptionalStringArgument(args, EXCEPTION_ARG_IDX, this); + int causeNestingLevel = CallableUtils.getOptionalIntArgument( + args, CAUSE_NESTING_LEVEL_ARG_IDX, 0, this); if (callPlace.hasNestedContent()) { boolean blockFailed; try { @@ -144,34 +143,4 @@ public class AssertFailsDirective implements TemplateDirectiveModel { return true; } - private String getAsString(TemplateModel value, String paramName, Environment env) - throws TemplateException { - if (value == null) { - return null; - } - if (value instanceof TemplateScalarModel) { - return ((TemplateScalarModel) value).getAsString(); - } else { - throw new BadParameterTypeException(paramName, "string", value, env); - } - } - - private Pattern getAsPattern(TemplateModel value, String paramName, Environment env) - throws TemplateException { - String s = getAsString(value, paramName, env); - return s != null ? Pattern.compile(s, Pattern.CASE_INSENSITIVE) : null; - } - - private int getAsInt(TemplateModel value, int defaultValue, String paramName, Environment env) - throws TemplateException { - if (value == null) { - return defaultValue; - } - if (value instanceof TemplateNumberModel) { - return ((TemplateNumberModel) value).getAsNumber().intValue(); - } else { - throw new BadParameterTypeException(paramName, "number", value, env); - } - } - } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/BadParameterTypeException.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/BadParameterTypeException.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/BadParameterTypeException.java deleted file mode 100644 index 34b7ec5..0000000 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/BadParameterTypeException.java +++ /dev/null @@ -1,60 +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 org.apache.freemarker.test.templateutil; - -import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.util._StringUtils; - -/** - * Indicates that a named directive/function parameter is not of the expected type. - * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked. - */ -public class BadParameterTypeException extends ParameterException { - - public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value, Environment env) { - this(parameterName, expectedType, value, null, null, env); - } - - public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value, - Exception cause, Environment env) { - this(parameterName, expectedType, value, null, cause, env); - } - - public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value, - String description, Environment env) { - this(parameterName, expectedType, value, description, null, env); - } - - public BadParameterTypeException( - String parameterName, String expectedType, TemplateModel value, String description, Exception cause, Environment env) { - super(parameterName, - "The type of the parameter " + _StringUtils.jQuote(parameterName) + " should be " + expectedType - + ", but the actual value was " + getTypeDescription(value) + "." - + (description != null ? " " + _StringUtils.jQuote(description) : ""), - cause, env); - } - - private static String getTypeDescription(TemplateModel value) { - //FIXME: This should call EvaluationUtil.getTypeDescriptionForDebugging, but that's not visible from here yet. - return value == null ? "Null" : value.getClass().getName(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/MissingRequiredParameterException.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/MissingRequiredParameterException.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/MissingRequiredParameterException.java deleted file mode 100644 index 19b2927..0000000 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/MissingRequiredParameterException.java +++ /dev/null @@ -1,51 +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 org.apache.freemarker.test.templateutil; - -import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.util._StringUtils; - -/** - * Indicates that a named directive/function parameter is missing. - * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked. - */ -class MissingRequiredParameterException extends ParameterException { - - public MissingRequiredParameterException(String parameterName, Environment env) { - this(parameterName, null, null, env); - } - - public MissingRequiredParameterException(String parameterName, Exception cause, Environment env) { - this(parameterName, null, cause, env); - } - - public MissingRequiredParameterException(String parameterName, String description, Environment env) { - this(parameterName, description, null, env); - } - - public MissingRequiredParameterException(String parameterName, String description, Exception cause, Environment env) { - super(parameterName, - "Required parameter " + _StringUtils.jQuote(parameterName) + " is missing, " - + "or the parameter value was null." - + (description != null ? " " + _StringUtils.jQuote(description) : ""), - cause, env); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/ParameterException.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/ParameterException.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/ParameterException.java deleted file mode 100644 index 2839ad3..0000000 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/ParameterException.java +++ /dev/null @@ -1,54 +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 org.apache.freemarker.test.templateutil; - -import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.TemplateException; - -/** - * An exception that is related to a named parameter of a directive or function. - * This is will be public and go into the org.apache.freemarker.core.ast when the method/directive stuff was reworked. - */ -abstract class ParameterException extends TemplateException { - - private final String parameterName; - - public ParameterException(String parameterName, Environment env) { - this(parameterName, null, null, env); - } - - public ParameterException(String parameterName, Exception cause, Environment env) { - this(parameterName, null, cause, env); - } - - public ParameterException(String parameterName, String description, Environment env) { - this(parameterName, description, null, env); - } - - public ParameterException(String parameterName, String description, Exception cause, Environment env) { - super(description, cause, env); - this.parameterName = parameterName; - } - - public String getParameterName() { - return parameterName; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/888ebe11/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/UnsupportedParameterException.java ---------------------------------------------------------------------- diff --git a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/UnsupportedParameterException.java b/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/UnsupportedParameterException.java deleted file mode 100644 index 4b0e274..0000000 --- a/freemarker-test-utils/src/main/java/org/apache/freemarker/test/templateutil/UnsupportedParameterException.java +++ /dev/null @@ -1,50 +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 org.apache.freemarker.test.templateutil; - -import org.apache.freemarker.core.Environment; -import org.apache.freemarker.core.util._StringUtils; - -/** - * Indicates that a named directive/function parameter is unsupported (like a typo). - * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked. - */ -class UnsupportedParameterException extends ParameterException { - - public UnsupportedParameterException(String parameterName, Environment env) { - this(parameterName, null, null, env); - } - - public UnsupportedParameterException(String parameterName, Exception cause, Environment env) { - this(parameterName, null, cause, env); - } - - public UnsupportedParameterException(String parameterName, String description, Environment env) { - this(parameterName, description, null, env); - } - - public UnsupportedParameterException(String parameterName, String description, Exception cause, Environment env) { - super(parameterName, - "Unsuppored parameter: " + _StringUtils.jQuote(parameterName) - + (description == null ? "." : ". " + _StringUtils.jQuote(description)), - cause, env); - } - -}