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 2017/08/07 22:41:30 UTC
[4/8] incubator-freemarker git commit: FREEMARKER-64: Removed
TemplateMethodModel,
using TemplateFunctionModel everywhere instead. Some refinement of existing
TemplateCallableModel API-s, most importantly,
the support for null argumenArrayLayout. Removed
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java
index 1a0e251..9d797ce 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java
@@ -42,7 +42,9 @@ import java.util.ResourceBundle;
import java.util.Set;
import java.util.WeakHashMap;
+import org.apache.freemarker.core.CallPlace;
import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.NonTemplateCallPlace;
import org.apache.freemarker.core.Version;
import org.apache.freemarker.core._CoreAPI;
import org.apache.freemarker.core._DelayedFTLTypeDescription;
@@ -55,8 +57,8 @@ import org.apache.freemarker.core.model.RichObjectWrapper;
import org.apache.freemarker.core.model.TemplateBooleanModel;
import org.apache.freemarker.core.model.TemplateCollectionModel;
import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelAdapter;
import org.apache.freemarker.core.model.TemplateModelException;
@@ -481,7 +483,7 @@ public class DefaultObjectWrapper implements RichObjectWrapper {
* Wraps a Java method so that it can be called from templates, without wrapping its parent ("this") object. The
* result is almost the same as that you would get by wrapping the parent object then getting the method from the
* resulting {@link TemplateHashModel} by name. Except, if the wrapped method is overloaded, with this method you
- * explicitly select a an overload, while otherwise you would get a {@link TemplateMethodModel} that selects an
+ * explicitly select an overload, while otherwise you would get a {@link OverloadedJavaMethodModel} that selects an
* overload each time it's called based on the argument values.
*
* @param object The object whose method will be called, or {@code null} if {@code method} is a static method.
@@ -489,8 +491,8 @@ public class DefaultObjectWrapper implements RichObjectWrapper {
* @param method The method to call, which must be an (inherited) member of the class of {@code object}, as
* described by {@link Method#invoke(Object, Object...)}
*/
- public TemplateMethodModel wrap(Object object, Method method) {
- return new JavaMethodModel(object, method, method.getParameterTypes(), this);
+ public TemplateFunctionModel wrap(Object object, Method method) {
+ return new SimpleJavaMethodModel(object, method, method.getParameterTypes(), this);
}
/**
@@ -582,7 +584,7 @@ public class DefaultObjectWrapper implements RichObjectWrapper {
// This is for transparent interop with other wrappers (and ourselves)
// Passing the targetClass allows e.g. a Jython-aware method that declares a
// PyObject as its argument to receive a PyObject from a Jython-aware TemplateModel
- // passed as an argument to TemplateMethodModel etc.
+ // passed as an argument to TemplateFunctionModel etc.
if (model instanceof AdapterTemplateModel) {
Object wrapped = ((AdapterTemplateModel) model).getAdaptedObject(targetClass);
if (targetClass == Object.class || targetClass.isInstance(wrapped)) {
@@ -1040,10 +1042,13 @@ public class DefaultObjectWrapper implements RichObjectWrapper {
* constructor. Overloaded constructors and varargs are supported. Only public constructors will be called.
*
* @param clazz The class whose constructor we will call.
- * @param arguments The list of {@link TemplateModel}-s to pass to the constructor after unwrapping them
+ * @param args The list of {@link TemplateModel}-s to pass to the constructor after unwrapping them
+ * @param callPlace Where the constructor is called from (which may contains information useful for overloaded
+ * constructor selection); you may want to use {@link NonTemplateCallPlace#INSTANCE}.
+ * if you call this from Java code.
* @return The instance created; it's not wrapped into {@link TemplateModel}.
*/
- public Object newInstance(Class<?> clazz, List/*<? extends TemplateModel>*/ arguments)
+ public Object newInstance(Class<?> clazz, TemplateModel[] args, CallPlace callPlace)
throws TemplateModelException {
try {
Object ctors = classIntrospector.get(clazz).get(ClassIntrospector.CONSTRUCTORS_KEY);
@@ -1052,19 +1057,19 @@ public class DefaultObjectWrapper implements RichObjectWrapper {
" has no public constructors.");
}
Constructor<?> ctor = null;
- Object[] objargs;
+ Object[] pojoArgs;
if (ctors instanceof SimpleMethod) {
SimpleMethod sm = (SimpleMethod) ctors;
ctor = (Constructor<?>) sm.getMember();
- objargs = sm.unwrapArguments(arguments, this);
+ pojoArgs = sm.unwrapArguments(args, this);
try {
- return ctor.newInstance(objargs);
+ return ctor.newInstance(pojoArgs);
} catch (Exception e) {
- if (e instanceof TemplateModelException) throw (TemplateModelException) e;
throw _MethodUtil.newInvocationTemplateModelException(null, ctor, e);
}
} else if (ctors instanceof OverloadedMethods) {
- final MemberAndArguments mma = ((OverloadedMethods) ctors).getMemberAndArguments(arguments, this);
+ // TODO [FM3] Utilize optional java type info in callPlace for overloaded method selection
+ final MemberAndArguments mma = ((OverloadedMethods) ctors).getMemberAndArguments(args, this);
try {
return mma.invokeConstructor(this);
} catch (Exception e) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/JavaMethodModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/JavaMethodModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/JavaMethodModel.java
index f89952e..6fb04c6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/JavaMethodModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/JavaMethodModel.java
@@ -19,88 +19,34 @@
package org.apache.freemarker.core.model.impl;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.List;
-
-import org.apache.freemarker.core._UnexpectedTypeErrorExplainerTemplateModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
+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.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
/**
- * Wraps a {@link Method} into the {@link TemplateMethodModel} interface. It is used by {@link BeanModel} to wrap
- * non-overloaded methods.
+ * Common super interface (marker interface) for {@link TemplateFunctionModel}-s that stand for Java methods; do not
+ * implement it yourself! It meant to be implemented inside FreeMarker only.
*/
-public final class JavaMethodModel extends SimpleMethod implements TemplateMethodModel,
- _UnexpectedTypeErrorExplainerTemplateModel {
- private final Object object;
- private final DefaultObjectWrapper wrapper;
-
- /**
- * Creates a model for a specific method on a specific object.
- * @param object the object to call the method on, or {@code null} for a static method.
- * @param method the method that will be invoked.
- * @param argTypes Either pass in {@code Method#getParameterTypes() method.getParameterTypes()} here,
- * or reuse an earlier result of that call (for speed). Not {@code null}.
- */
- JavaMethodModel(Object object, Method method, Class[] argTypes, DefaultObjectWrapper wrapper) {
- super(method, argTypes);
- this.object = object;
- this.wrapper = wrapper;
- }
+public interface JavaMethodModel extends TemplateFunctionModel {
/**
- * Invokes the method, passing it the arguments from the list.
+ * Calls {@link #execute(TemplateModel[], CallPlace, Environment)}, but it emphasizes that the
+ * {@link Environment} parameters is ignored, and passes {@code null} for it.
+ *
+ * @param args As {@link #getFunctionArgumentArrayLayout()} always return {@code null} in
+ * {@link JavaMethodModel}-s, the length of this array corresponds to the number of actual arguments
+ * specified on the call site, and all parameters will be positional.
+ *
+ * @param callPlace Same as with {@link #execute(TemplateModel[], CallPlace, Environment)}.
*/
- @Override
- public TemplateModel execute(List<? extends TemplateModel> args) throws TemplateModelException {
- try {
- return wrapper.invokeMethod(object, (Method) getMember(),
- unwrapArguments(args, wrapper));
- } catch (TemplateModelException e) {
- throw e;
- } catch (Exception e) {
- throw _MethodUtil.newInvocationTemplateModelException(object, getMember(), e);
- }
- }
-
- @Override
- public String toString() {
- return getMember().toString();
- }
+ TemplateModel execute(TemplateModel[] args, CallPlace callPlace) throws TemplateException;
/**
- * Implementation of experimental interface; don't use it, no backward compatibility guarantee!
+ * Always returns {@code null} for {@link JavaMethodModel}-s; hence, only positional parameters are supported.
*/
@Override
- public Object[] explainTypeError(Class[] expectedClasses) {
- final Member member = getMember();
- if (!(member instanceof Method)) {
- return null; // This shouldn't occur
- }
- Method m = (Method) member;
-
- final Class returnType = m.getReturnType();
- if (returnType == null || returnType == void.class || returnType == Void.class) {
- return null; // Calling it won't help
- }
-
- String mName = m.getName();
- if (mName.startsWith("get") && mName.length() > 3 && Character.isUpperCase(mName.charAt(3))
- && (m.getParameterTypes().length == 0)) {
- return new Object[] {
- "Maybe using obj.something instead of obj.getSomething will yield the desired value." };
- } else if (mName.startsWith("is") && mName.length() > 2 && Character.isUpperCase(mName.charAt(2))
- && (m.getParameterTypes().length == 0)) {
- return new Object[] {
- "Maybe using obj.something instead of obj.isSomething will yield the desired value." };
- } else {
- return new Object[] {
- "Maybe using obj.something(",
- (m.getParameterTypes().length != 0 ? "params" : ""),
- ") instead of obj.something will yield the desired value" };
- }
- }
-
-}
\ No newline at end of file
+ ArgumentArrayLayout getFunctionArgumentArrayLayout();
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedFixArgsMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedFixArgsMethods.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedFixArgsMethods.java
index bff717d..4a8b69b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedFixArgsMethods.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedFixArgsMethods.java
@@ -18,10 +18,7 @@
*/
package org.apache.freemarker.core.model.impl;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
+import org.apache.freemarker.core.model.Constants;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
@@ -36,28 +33,28 @@ class OverloadedFixArgsMethods extends OverloadedMethodsSubset {
}
@Override
- Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
+ Class<?>[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
return memberDesc.getParamTypes();
}
@Override
- void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes) {
+ void afterWideningUnwrappingHints(Class<?>[] paramTypes, int[] paramNumericalTypes) {
// Do nothing
}
@Override
- MaybeEmptyMemberAndArguments getMemberAndArguments(List tmArgs, DefaultObjectWrapper unwrapper)
+ MaybeEmptyMemberAndArguments getMemberAndArguments(TemplateModel[] tmArgs, DefaultObjectWrapper unwrapper)
throws TemplateModelException {
if (tmArgs == null) {
// null is treated as empty args
- tmArgs = Collections.EMPTY_LIST;
+ tmArgs = Constants.EMPTY_TEMPLATE_MODEL_ARRAY;
}
- final int argCount = tmArgs.size();
- final Class[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
+ final int argCount = tmArgs.length;
+ final Class<?>[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
if (unwrappingHintsByParamCount.length <= argCount) {
return EmptyMemberAndArguments.WRONG_NUMBER_OF_ARGUMENTS;
}
- Class[] unwarppingHints = unwrappingHintsByParamCount[argCount];
+ Class<?>[] unwarppingHints = unwrappingHintsByParamCount[argCount];
if (unwarppingHints == null) {
return EmptyMemberAndArguments.WRONG_NUMBER_OF_ARGUMENTS;
}
@@ -69,10 +66,9 @@ class OverloadedFixArgsMethods extends OverloadedMethodsSubset {
typeFlags = null;
}
- Iterator it = tmArgs.iterator();
- for (int i = 0; i < argCount; ++i) {
+ for (int i = 0; i < argCount; i++) {
Object pojo = unwrapper.tryUnwrapTo(
- (TemplateModel) it.next(),
+ tmArgs[i],
unwarppingHints[i],
typeFlags != null ? typeFlags[i] : 0);
if (pojo == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedJavaMethodModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedJavaMethodModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedJavaMethodModel.java
new file mode 100644
index 0000000..1877687
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedJavaMethodModel.java
@@ -0,0 +1,86 @@
+/*
+ * 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.core.model.impl;
+
+
+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.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+/**
+ * Wraps a set of same-name overloaded methods behind {@link TemplateFunctionModel} interface,
+ * like if it was a single method; chooses among them behind the scenes on call-time based on the argument values
+ * (and the {@link CallPlace}).
+ *
+ * @see SimpleJavaMethodModel
+ */
+class OverloadedJavaMethodModel implements JavaMethodModel {
+
+ private final Object object;
+ private final OverloadedMethods overloadedMethods;
+ private final DefaultObjectWrapper wrapper;
+
+ OverloadedJavaMethodModel(Object object, OverloadedMethods overloadedMethods, DefaultObjectWrapper wrapper) {
+ this.object = object;
+ this.overloadedMethods = overloadedMethods;
+ this.wrapper = wrapper;
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace) throws TemplateException {
+ return execute(args, callPlace, null);
+ }
+
+ /**
+ * See {@link #execute(TemplateModel[], CallPlace)}; the {@link Environment} parameter can be {@code null} in this
+ * implementation. The actual method to call from several overloaded methods will be chosen based on the classes of
+ * the arguments.
+ *
+ * @throws TemplateModelException
+ * if the method cannot be chosen unambiguously.
+ */
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment envUnused)
+ throws TemplateModelException {
+ // TODO [FM3] Utilize optional java type info in callPlace for overloaded method selection
+ MemberAndArguments maa = overloadedMethods.getMemberAndArguments(args, wrapper);
+ try {
+ return maa.invokeMethod(wrapper, object);
+ } catch (Exception e) {
+ if (e instanceof TemplateModelException) throw (TemplateModelException) e;
+
+ throw _MethodUtil.newInvocationTemplateModelException(
+ object,
+ maa.getCallableMemberDescriptor(),
+ e);
+ }
+ }
+
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ // Required to return null! See inherited JavaDoc.
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
index 1ba1a56..fad854d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
@@ -23,7 +23,6 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import org.apache.freemarker.core._DelayedConversionToString;
import org.apache.freemarker.core._ErrorDescriptionBuilder;
@@ -52,12 +51,12 @@ final class OverloadedMethods {
}
void addMethod(Method method) {
- final Class[] paramTypes = method.getParameterTypes();
+ final Class<?>[] paramTypes = method.getParameterTypes();
addCallableMemberDescriptor(new ReflectionCallableMemberDescriptor(method, paramTypes));
}
- void addConstructor(Constructor constr) {
- final Class[] paramTypes = constr.getParameterTypes();
+ void addConstructor(Constructor<?> constr) {
+ final Class<?>[] paramTypes = constr.getParameterTypes();
addCallableMemberDescriptor(new ReflectionCallableMemberDescriptor(constr, paramTypes));
}
@@ -72,7 +71,7 @@ final class OverloadedMethods {
}
}
- MemberAndArguments getMemberAndArguments(List/*<TemplateModel>*/ tmArgs, DefaultObjectWrapper unwrapper)
+ MemberAndArguments getMemberAndArguments(TemplateModel[] tmArgs, DefaultObjectWrapper unwrapper)
throws TemplateModelException {
// Try to find a oms args match:
MaybeEmptyMemberAndArguments fixArgsRes = fixArgMethods.getMemberAndArguments(tmArgs, unwrapper);
@@ -104,7 +103,7 @@ final class OverloadedMethods {
private Object[] toCompositeErrorMessage(
final EmptyMemberAndArguments fixArgsEmptyRes, final EmptyMemberAndArguments varargsEmptyRes,
- List tmArgs) {
+ TemplateModel[] tmArgs) {
final Object[] argsErrorMsg;
if (varargsEmptyRes != null) {
if (fixArgsEmptyRes == null || fixArgsEmptyRes.isNumberOfArgumentsWrong()) {
@@ -123,7 +122,7 @@ final class OverloadedMethods {
return argsErrorMsg;
}
- private Object[] toErrorMessage(EmptyMemberAndArguments res, List/*<TemplateModel>*/ tmArgs) {
+ private Object[] toErrorMessage(EmptyMemberAndArguments res, TemplateModel[] tmArgs) {
final Object[] unwrappedArgs = res.getUnwrappedArguments();
return new Object[] {
res.getErrorDescription(),
@@ -143,23 +142,26 @@ final class OverloadedMethods {
@Override
protected String doConversion(Object obj) {
- final Iterator fixArgMethodsIter = fixArgMethods.getMemberDescriptors();
- final Iterator varargMethodsIter = varargMethods != null ? varargMethods.getMemberDescriptors() : null;
+ final Iterator<ReflectionCallableMemberDescriptor> fixArgMethodsIter
+ = fixArgMethods.getMemberDescriptors();
+ final Iterator<ReflectionCallableMemberDescriptor> varargMethodsIter
+ = varargMethods != null ? varargMethods.getMemberDescriptors() : null;
- boolean hasMethods = fixArgMethodsIter.hasNext() || (varargMethodsIter != null && varargMethodsIter.hasNext());
+ boolean hasMethods = fixArgMethodsIter.hasNext()
+ || (varargMethodsIter != null && varargMethodsIter.hasNext());
if (hasMethods) {
StringBuilder sb = new StringBuilder();
- HashSet fixArgMethods = new HashSet();
+ HashSet<CallableMemberDescriptor> fixArgMethods = new HashSet<>();
while (fixArgMethodsIter.hasNext()) {
if (sb.length() != 0) sb.append(",\n");
sb.append(" ");
- CallableMemberDescriptor callableMemberDesc = (CallableMemberDescriptor) fixArgMethodsIter.next();
+ CallableMemberDescriptor callableMemberDesc = fixArgMethodsIter.next();
fixArgMethods.add(callableMemberDesc);
sb.append(callableMemberDesc.getDeclaration());
}
if (varargMethodsIter != null) {
while (varargMethodsIter.hasNext()) {
- CallableMemberDescriptor callableMemberDesc = (CallableMemberDescriptor) varargMethodsIter.next();
+ CallableMemberDescriptor callableMemberDesc = varargMethodsIter.next();
if (!fixArgMethods.contains(callableMemberDesc)) {
if (sb.length() != 0) sb.append(",\n");
sb.append(" ");
@@ -181,15 +183,16 @@ final class OverloadedMethods {
* allows finding a matching overload.
*/
private void addMarkupBITipAfterNoNoMarchIfApplicable(_ErrorDescriptionBuilder edb,
- List tmArgs) {
- for (int argIdx = 0; argIdx < tmArgs.size(); argIdx++) {
- Object tmArg = tmArgs.get(argIdx);
+ TemplateModel[] tmArgs) {
+ for (int argIdx = 0; argIdx < tmArgs.length; argIdx++) {
+ TemplateModel tmArg = tmArgs[argIdx];
if (tmArg instanceof TemplateMarkupOutputModel) {
- for (Iterator membDescs = fixArgMethods.getMemberDescriptors(); membDescs.hasNext();) {
- CallableMemberDescriptor membDesc = (CallableMemberDescriptor) membDescs.next();
- Class[] paramTypes = membDesc.getParamTypes();
+ for (Iterator<ReflectionCallableMemberDescriptor> membDescs = fixArgMethods.getMemberDescriptors();
+ membDescs.hasNext(); ) {
+ CallableMemberDescriptor membDesc = membDescs.next();
+ Class<?>[] paramTypes = membDesc.getParamTypes();
- Class paramType = null;
+ Class<?> paramType = null;
if (membDesc.isVarargs() && argIdx >= paramTypes.length - 1) {
paramType = paramTypes[paramTypes.length - 1];
if (paramType.isArray()) {
@@ -201,7 +204,7 @@ final class OverloadedMethods {
}
if (paramType != null) {
if (paramType.isAssignableFrom(String.class) && !paramType.isAssignableFrom(tmArg.getClass())) {
- edb.tip(JavaMethodModel.MARKUP_OUTPUT_TO_STRING_TIP);
+ edb.tip(SimpleJavaMethodModel.MARKUP_OUTPUT_TO_STRING_TIP);
return;
}
}
@@ -210,10 +213,10 @@ final class OverloadedMethods {
}
}
- private _DelayedConversionToString getTMActualParameterTypes(List arguments) {
- final String[] argumentTypeDescs = new String[arguments.size()];
- for (int i = 0; i < arguments.size(); i++) {
- argumentTypeDescs[i] = FTLUtil.getTypeDescription((TemplateModel) arguments.get(i));
+ private _DelayedConversionToString getTMActualParameterTypes(TemplateModel[] args) {
+ final String[] argumentTypeDescs = new String[args.length];
+ for (int i = 0; i < args.length; i++) {
+ argumentTypeDescs[i] = FTLUtil.getTypeDescription(args[i]);
}
return new DelayedCallSignatureToString(argumentTypeDescs) {
@@ -227,7 +230,7 @@ final class OverloadedMethods {
}
private Object getUnwrappedActualParameterTypes(Object[] unwrappedArgs) {
- final Class[] argumentTypes = new Class[unwrappedArgs.length];
+ final Class<?>[] argumentTypes = new Class<?>[unwrappedArgs.length];
for (int i = 0; i < unwrappedArgs.length; i++) {
Object unwrappedArg = unwrappedArgs[i];
argumentTypes[i] = unwrappedArg != null ? unwrappedArg.getClass() : null;
@@ -238,7 +241,7 @@ final class OverloadedMethods {
@Override
String argumentToString(Object argType) {
return argType != null
- ? _ClassUtil.getShortClassName((Class) argType)
+ ? _ClassUtil.getShortClassName((Class<?>) argType)
: _ClassUtil.getShortClassNameOfObject(null);
}
@@ -247,7 +250,7 @@ final class OverloadedMethods {
private abstract class DelayedCallSignatureToString extends _DelayedConversionToString {
- public DelayedCallSignatureToString(Object[] argTypeArray) {
+ DelayedCallSignatureToString(Object[] argTypeArray) {
super(argTypeArray);
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsModel.java
deleted file mode 100644
index 72ca642..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsModel.java
+++ /dev/null
@@ -1,65 +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.core.model.impl;
-
-
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-/**
- * Wraps a set of same-name overloaded methods behind {@link TemplateMethodModel} interface,
- * like if it was a single method, chooses among them behind the scenes on call-time based on the argument values.
- */
-class OverloadedMethodsModel implements TemplateMethodModel {
- private final Object object;
- private final OverloadedMethods overloadedMethods;
- private final DefaultObjectWrapper wrapper;
-
- OverloadedMethodsModel(Object object, OverloadedMethods overloadedMethods, DefaultObjectWrapper wrapper) {
- this.object = object;
- this.overloadedMethods = overloadedMethods;
- this.wrapper = wrapper;
- }
-
- /**
- * Invokes the method, passing it the arguments from the list. The actual
- * method to call from several overloaded methods will be chosen based
- * on the classes of the arguments.
- * @throws TemplateModelException if the method cannot be chosen
- * unambiguously.
- */
- @Override
- public TemplateModel execute(List<? extends TemplateModel> args) throws TemplateModelException {
- MemberAndArguments maa = overloadedMethods.getMemberAndArguments(args, wrapper);
- try {
- return maa.invokeMethod(wrapper, object);
- } catch (Exception e) {
- if (e instanceof TemplateModelException) throw (TemplateModelException) e;
-
- throw _MethodUtil.newInvocationTemplateModelException(
- object,
- maa.getCallableMemberDescriptor(),
- e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsSubset.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsSubset.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsSubset.java
index e783af8..aab6d43 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsSubset.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethodsSubset.java
@@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
import org.apache.freemarker.core.util._ClassUtil;
import org.apache.freemarker.core.util._NullArgumentException;
@@ -52,7 +53,7 @@ abstract class OverloadedMethodsSubset {
ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY[0] = ALL_ZEROS_ARRAY;
}
- private Class[/*number of args*/][/*arg index*/] unwrappingHintsByParamCount;
+ private Class<?>[/*number of args*/][/*arg index*/] unwrappingHintsByParamCount;
/**
* Tells what types occur at a given parameter position with a bit field. See {@link TypeFlags}.
@@ -61,10 +62,10 @@ abstract class OverloadedMethodsSubset {
// TODO: This can cause memory-leak when classes are re-loaded. However, first the genericClassIntrospectionCache
// and such need to be oms in this regard.
- private final Map/*<ArgumentTypes, MaybeEmptyCallableMemberDescriptor>*/ argTypesToMemberDescCache
- = new ConcurrentHashMap(6, 0.75f, 1);
+ private final Map<ArgumentTypes, MaybeEmptyCallableMemberDescriptor> argTypesToMemberDescCache
+ = new ConcurrentHashMap<>(6, 0.75f, 1);
- private final List/*<ReflectionCallableMemberDescriptor>*/ memberDescs = new LinkedList();
+ private final List<ReflectionCallableMemberDescriptor> memberDescs = new LinkedList<>();
OverloadedMethodsSubset() {
//
@@ -75,7 +76,7 @@ abstract class OverloadedMethodsSubset {
// Warning: Do not modify this array, or put it into unwrappingHintsByParamCount by reference, as the arrays
// inside that are modified!
- final Class[] prepedParamTypes = preprocessParameterTypes(memberDesc);
+ final Class<?>[] prepedParamTypes = preprocessParameterTypes(memberDesc);
final int paramCount = prepedParamTypes.length; // Must be the same as the length of the original param list
// Merge these unwrapping hints with the existing table of hints:
@@ -83,13 +84,13 @@ abstract class OverloadedMethodsSubset {
unwrappingHintsByParamCount = new Class[paramCount + 1][];
unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
} else if (unwrappingHintsByParamCount.length <= paramCount) {
- Class[][] newUnwrappingHintsByParamCount = new Class[paramCount + 1][];
+ Class<?>[][] newUnwrappingHintsByParamCount = new Class[paramCount + 1][];
System.arraycopy(unwrappingHintsByParamCount, 0, newUnwrappingHintsByParamCount, 0,
unwrappingHintsByParamCount.length);
unwrappingHintsByParamCount = newUnwrappingHintsByParamCount;
unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
} else {
- Class[] unwrappingHints = unwrappingHintsByParamCount[paramCount];
+ Class<?>[] unwrappingHints = unwrappingHintsByParamCount[paramCount];
if (unwrappingHints == null) {
unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
} else {
@@ -123,7 +124,7 @@ abstract class OverloadedMethodsSubset {
afterWideningUnwrappingHints(prepedParamTypes, typeFlagsByParamIdx);
}
- Class[][] getUnwrappingHintsByParamCount() {
+ Class<?>[][] getUnwrappingHintsByParamCount() {
return unwrappingHintsByParamCount;
}
@@ -131,12 +132,11 @@ abstract class OverloadedMethodsSubset {
justification="Locks for member descriptor creation only")
final MaybeEmptyCallableMemberDescriptor getMemberDescriptorForArgs(Object[] args, boolean varArg) {
ArgumentTypes argTypes = new ArgumentTypes(args);
- MaybeEmptyCallableMemberDescriptor memberDesc
- = (MaybeEmptyCallableMemberDescriptor) argTypesToMemberDescCache.get(argTypes);
+ MaybeEmptyCallableMemberDescriptor memberDesc = argTypesToMemberDescCache.get(argTypes);
if (memberDesc == null) {
// Synchronized so that we won't unnecessarily invoke the same member desc. for multiple times in parallel.
synchronized (argTypesToMemberDescCache) {
- memberDesc = (MaybeEmptyCallableMemberDescriptor) argTypesToMemberDescCache.get(argTypes);
+ memberDesc = argTypesToMemberDescCache.get(argTypes);
if (memberDesc == null) {
memberDesc = argTypes.getMostSpecific(memberDescs, varArg);
argTypesToMemberDescCache.put(argTypes, memberDesc);
@@ -146,14 +146,14 @@ abstract class OverloadedMethodsSubset {
return memberDesc;
}
- Iterator/*<ReflectionCallableMemberDescriptor>*/ getMemberDescriptors() {
+ Iterator<ReflectionCallableMemberDescriptor> getMemberDescriptors() {
return memberDescs.iterator();
}
- abstract Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc);
- abstract void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes);
+ abstract Class<?>[] preprocessParameterTypes(CallableMemberDescriptor memberDesc);
+ abstract void afterWideningUnwrappingHints(Class<?>[] paramTypes, int[] paramNumericalTypes);
- abstract MaybeEmptyMemberAndArguments getMemberAndArguments(List/*<TemplateModel>*/ tmArgs,
+ abstract MaybeEmptyMemberAndArguments getMemberAndArguments(TemplateModel[] tmArgs,
DefaultObjectWrapper unwrapper) throws TemplateModelException;
/**
@@ -168,7 +168,7 @@ abstract class OverloadedMethodsSubset {
* @param c1 Parameter type 1
* @param c2 Parameter type 2
*/
- protected Class getCommonSupertypeForUnwrappingHint(Class c1, Class c2) {
+ Class<?> getCommonSupertypeForUnwrappingHint(Class<?> c1, Class<?> c2) {
if (c1 == c2) return c1;
// This also means that the hint for (Integer, Integer) will be Integer, not just Number. This is consistent
// with how non-overloaded method hints work.
@@ -214,7 +214,7 @@ abstract class OverloadedMethodsSubset {
// - One of classes was a primitive type
// - One of classes was a numerical type (either boxing type or primitive)
- Set commonTypes = _MethodUtil.getAssignables(c1, c2);
+ Set<Class<?>> commonTypes = _MethodUtil.getAssignables(c1, c2);
commonTypes.retainAll(_MethodUtil.getAssignables(c2, c1));
if (commonTypes.isEmpty()) {
// Can happen when at least one of the arguments is an interface, as
@@ -226,11 +226,11 @@ abstract class OverloadedMethodsSubset {
// because of interfaces. I.e., if you call this method for String.class
// and Number.class, you'll have Comparable, Serializable, and Object as
// maximal elements.
- List max = new ArrayList();
- listCommonTypes: for (Iterator commonTypesIter = commonTypes.iterator(); commonTypesIter.hasNext(); ) {
- Class clazz = (Class) commonTypesIter.next();
- for (Iterator maxIter = max.iterator(); maxIter.hasNext(); ) {
- Class maxClazz = (Class) maxIter.next();
+ List<Class<?>> max = new ArrayList<>();
+ listCommonTypes:
+ for (Class<?> clazz : commonTypes) {
+ for (Iterator<Class<?>> maxIter = max.iterator(); maxIter.hasNext(); ) {
+ Class<?> maxClazz = maxIter.next();
if (_MethodUtil.isMoreOrSameSpecificParameterType(maxClazz, clazz, false /*bugfixed [1]*/, 0) != 0) {
// clazz can't be maximal, if there's already a more specific or equal maximal than it.
continue listCommonTypes;
@@ -251,8 +251,8 @@ abstract class OverloadedMethodsSubset {
if (max.size() > 1) { // we have an ambiguity
// Find the non-interface class
- for (Iterator it = max.iterator(); it.hasNext(); ) {
- Class maxCl = (Class) it.next();
+ for (Iterator<Class<?>> it = max.iterator(); it.hasNext(); ) {
+ Class<?> maxCl = it.next();
if (!maxCl.isInterface()) {
if (maxCl != Object.class) { // This actually shouldn't ever happen, but to be sure...
// If it's not Object, we use it as the most specific
@@ -278,7 +278,7 @@ abstract class OverloadedMethodsSubset {
}
}
- return (Class) max.get(0);
+ return max.get(0);
}
/**
@@ -286,7 +286,7 @@ abstract class OverloadedMethodsSubset {
* count or if we are in pre-2.3.21 mode, or {@link #ALL_ZEROS_ARRAY} if there were no parameters that turned
* on a flag. The returned {@code int}-s are one or more {@link TypeFlags} constants binary "or"-ed together.
*/
- final protected int[] getTypeFlags(int paramCount) {
+ final int[] getTypeFlags(int paramCount) {
return typeFlagsByParamCount != null && typeFlagsByParamCount.length > paramCount
? typeFlagsByParamCount[paramCount]
: null;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedVarArgsMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedVarArgsMethods.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedVarArgsMethods.java
index 6547923..8085693 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedVarArgsMethods.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedVarArgsMethods.java
@@ -19,10 +19,8 @@
package org.apache.freemarker.core.model.impl;
import java.lang.reflect.Array;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
+import org.apache.freemarker.core.model.Constants;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
@@ -41,10 +39,10 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
* Replaces the last parameter type with the array component type of it.
*/
@Override
- Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
- final Class[] preprocessedParamTypes = memberDesc.getParamTypes().clone();
+ Class<?>[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
+ final Class<?>[] preprocessedParamTypes = memberDesc.getParamTypes().clone();
int ln = preprocessedParamTypes.length;
- final Class varArgsCompType = preprocessedParamTypes[ln - 1].getComponentType();
+ final Class<?> varArgsCompType = preprocessedParamTypes[ln - 1].getComponentType();
if (varArgsCompType == null) {
throw new BugException("Only varargs methods should be handled here");
}
@@ -53,7 +51,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
}
@Override
- void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes) {
+ void afterWideningUnwrappingHints(Class<?>[] paramTypes, int[] paramNumericalTypes) {
// Overview
// --------
//
@@ -67,7 +65,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
// So we only update the already existing hints. Remember that we already have m(t1, t2) there.
final int paramCount = paramTypes.length;
- final Class[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
+ final Class<?>[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
// The case of e(t1, t2), e(t1, t2, t2), e(t1, t2, t2, t2), ..., where e is an *earlierly* added method.
// When that was added, this method wasn't added yet, so it had no chance updating the hints of this method,
@@ -75,7 +73,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
// FIXME: Only needed if m(t1, t2) was filled an empty slot, otherwise whatever was there was already
// widened by the preceding hints, so this will be a no-op.
for (int i = paramCount - 1; i >= 0; i--) {
- final Class[] previousHints = unwrappingHintsByParamCount[i];
+ final Class<?>[] previousHints = unwrappingHintsByParamCount[i];
if (previousHints != null) {
widenHintsToCommonSupertypes(
paramCount,
@@ -88,7 +86,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
// so we do that now:
// FIXME: Same as above; it's often unnecessary.
if (paramCount + 1 < unwrappingHintsByParamCount.length) {
- Class[] oneLongerHints = unwrappingHintsByParamCount[paramCount + 1];
+ Class<?>[] oneLongerHints = unwrappingHintsByParamCount[paramCount + 1];
if (oneLongerHints != null) {
widenHintsToCommonSupertypes(
paramCount,
@@ -114,8 +112,8 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
}
private void widenHintsToCommonSupertypes(
- int paramCountOfWidened, Class[] wideningTypes, int[] wideningTypeFlags) {
- final Class[] typesToWiden = getUnwrappingHintsByParamCount()[paramCountOfWidened];
+ int paramCountOfWidened, Class<?>[] wideningTypes, int[] wideningTypeFlags) {
+ final Class<?>[] typesToWiden = getUnwrappingHintsByParamCount()[paramCountOfWidened];
if (typesToWiden == null) {
return; // no such overload exists; nothing to widen
}
@@ -127,7 +125,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
typesToWiden[i] = getCommonSupertypeForUnwrappingHint(typesToWiden[i], wideningTypes[i]);
}
if (typesToWidenLen > wideningTypesLen) {
- Class varargsComponentType = wideningTypes[wideningTypesLen - 1];
+ Class<?> varargsComponentType = wideningTypes[wideningTypesLen - 1];
for (int i = wideningTypesLen; i < typesToWidenLen; ++i) {
typesToWiden[i] = getCommonSupertypeForUnwrappingHint(typesToWiden[i], varargsComponentType);
}
@@ -137,20 +135,20 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
}
@Override
- MaybeEmptyMemberAndArguments getMemberAndArguments(List tmArgs, DefaultObjectWrapper unwrapper)
+ MaybeEmptyMemberAndArguments getMemberAndArguments(TemplateModel[] tmArgs, DefaultObjectWrapper unwrapper)
throws TemplateModelException {
if (tmArgs == null) {
// null is treated as empty args
- tmArgs = Collections.EMPTY_LIST;
+ tmArgs = Constants.EMPTY_TEMPLATE_MODEL_ARRAY;
}
- final int argsLen = tmArgs.size();
- final Class[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
+ final int argsLen = tmArgs.length;
+ final Class<?>[][] unwrappingHintsByParamCount = getUnwrappingHintsByParamCount();
final Object[] pojoArgs = new Object[argsLen];
int[] typesFlags = null;
// Going down starting from methods with args.length + 1 parameters, because we must try to match against a case
// where all specified args are fixargs, and we have 0 varargs.
outer: for (int paramCount = Math.min(argsLen + 1, unwrappingHintsByParamCount.length - 1); paramCount >= 0; --paramCount) {
- Class[] unwarappingHints = unwrappingHintsByParamCount[paramCount];
+ Class<?>[] unwarappingHints = unwrappingHintsByParamCount[paramCount];
if (unwarappingHints == null) {
if (paramCount == 0) {
return EmptyMemberAndArguments.WRONG_NUMBER_OF_ARGUMENTS;
@@ -164,11 +162,10 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
}
// Try to unwrap the arguments
- Iterator it = tmArgs.iterator();
- for (int i = 0; i < argsLen; ++i) {
+ for (int i = 0; i < argsLen; i++) {
int paramIdx = i < paramCount ? i : paramCount - 1;
Object pojo = unwrapper.tryUnwrapTo(
- (TemplateModel) it.next(),
+ tmArgs[i],
unwarappingHints[paramIdx],
typesFlags != null ? typesFlags[paramIdx] : 0);
if (pojo == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
@@ -187,7 +184,7 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
if (argsOrErrorIdx instanceof Object[]) {
pojoArgsWithArray = (Object[]) argsOrErrorIdx;
} else {
- return EmptyMemberAndArguments.noCompatibleOverload(((Integer) argsOrErrorIdx).intValue());
+ return EmptyMemberAndArguments.noCompatibleOverload((Integer) argsOrErrorIdx);
}
if (typesFlags != null) {
// Note that overloaded method selection has already accounted for overflow errors when the method
@@ -210,11 +207,11 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
* order (1-based index) of the argument that couldn't be unwrapped.
*/
private Object replaceVarargsSectionWithArray(
- Object[] args, List modelArgs, CallableMemberDescriptor memberDesc, DefaultObjectWrapper unwrapper)
- throws TemplateModelException {
- final Class[] paramTypes = memberDesc.getParamTypes();
+ Object[] args, TemplateModel[] tmArgs, CallableMemberDescriptor memberDesc, DefaultObjectWrapper unwrapper)
+ throws TemplateModelException {
+ final Class<?>[] paramTypes = memberDesc.getParamTypes();
final int paramCount = paramTypes.length;
- final Class varArgsCompType = paramTypes[paramCount - 1].getComponentType();
+ final Class<?> varArgsCompType = paramTypes[paramCount - 1].getComponentType();
final int totalArgCount = args.length;
final int fixArgCount = paramCount - 1;
if (args.length != paramCount) {
@@ -222,18 +219,18 @@ class OverloadedVarArgsMethods extends OverloadedMethodsSubset {
System.arraycopy(args, 0, packedArgs, 0, fixArgCount);
Object varargs = Array.newInstance(varArgsCompType, totalArgCount - fixArgCount);
for (int i = fixArgCount; i < totalArgCount; ++i) {
- Object val = unwrapper.tryUnwrapTo((TemplateModel) modelArgs.get(i), varArgsCompType);
+ Object val = unwrapper.tryUnwrapTo(tmArgs[i], varArgsCompType);
if (val == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
- return Integer.valueOf(i + 1);
+ return i + 1;
}
Array.set(varargs, i - fixArgCount, val);
}
packedArgs[fixArgCount] = varargs;
return packedArgs;
} else {
- Object val = unwrapper.tryUnwrapTo((TemplateModel) modelArgs.get(fixArgCount), varArgsCompType);
+ Object val = unwrapper.tryUnwrapTo(tmArgs[fixArgCount], varArgsCompType);
if (val == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
- return Integer.valueOf(fixArgCount + 1);
+ return fixArgCount + 1;
}
Object array = Array.newInstance(varArgsCompType, 1);
Array.set(array, 0, val);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/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 457c7ef..b4cca30 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
@@ -22,16 +22,19 @@ package org.apache.freemarker.core.model.impl;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core._CallableUtils;
import org.apache.freemarker.core._DelayedJQuote;
import org.apache.freemarker.core._TemplateModelException;
-import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
@@ -50,11 +53,7 @@ import org.apache.freemarker.core.model.TemplateModelException;
* for MessageFormat with arguments arg1, arg2 and arg3</li>
* </ul>
*/
-public class ResourceBundleModel
- extends
- BeanModel
- implements
- TemplateMethodModel {
+public class ResourceBundleModel extends BeanModel implements TemplateFunctionModel {
private Hashtable<String, MessageFormat> formats = null;
@@ -108,25 +107,23 @@ public class ResourceBundleModel
* rest of the arguments. The created MessageFormats are cached for later reuse.
*/
@Override
- public TemplateModel execute(List<? extends TemplateModel> args)
- throws TemplateModelException {
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
// Must have at least one argument - the key
- if (args.size() < 1)
- throw new TemplateModelException("No message key was specified");
+ if (args.length < 1)
+ throw new TemplateException("No message key was specified", env);
// Read it
- Iterator<? extends TemplateModel> it = args.iterator();
- String key = unwrap((TemplateModel) it.next()).toString();
+ String key = _CallableUtils.castArgToString(args, 0);
try {
- if (!it.hasNext()) {
+ if (args.length == 1) {
return wrap(((ResourceBundle) object).getObject(key));
}
-
+
// Copy remaining arguments into an Object[]
- int paramsLen = args.size() - 1;
+ int paramsLen = args.length - 1;
Object[] params = new Object[paramsLen];
for (int i = 0; i < paramsLen; ++i)
- params[i] = unwrap(it.next());
-
+ params[i] = unwrap(args[1 + i]);
+
// Invoke format
return new BeanAndStringModel(format(key, params), wrapper);
} catch (MissingResourceException e) {
@@ -136,6 +133,11 @@ public class ResourceBundleModel
}
}
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ return null;
+ }
+
/**
* Provides direct access to caching format engine from code (instead of from script).
*/
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleJavaMethodModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleJavaMethodModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleJavaMethodModel.java
new file mode 100644
index 0000000..d27d131
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleJavaMethodModel.java
@@ -0,0 +1,123 @@
+/*
+ * 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.core.model.impl;
+
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core._UnexpectedTypeErrorExplainerTemplateModel;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+/**
+ * Wraps a {@link Method} into the {@link TemplateFunctionModel} interface. It is used by {@link BeanModel} to wrap
+ * non-overloaded methods.
+ *
+ * @see OverloadedJavaMethodModel
+ */
+public final class SimpleJavaMethodModel extends SimpleMethod implements JavaMethodModel,
+ _UnexpectedTypeErrorExplainerTemplateModel {
+ private final Object object;
+ private final DefaultObjectWrapper wrapper;
+
+ /**
+ * Creates a model for a specific method on a specific object.
+ * @param object the object to call the method on, or {@code null} for a static method.
+ * @param method the method that will be invoked.
+ * @param argTypes Either pass in {@code Method#getParameterTypes() method.getParameterTypes()} here,
+ * or reuse an earlier result of that call (for speed). Not {@code null}.
+ */
+ SimpleJavaMethodModel(Object object, Method method, Class[] argTypes, DefaultObjectWrapper wrapper) {
+ super(method, argTypes);
+ this.object = object;
+ this.wrapper = wrapper;
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace) throws TemplateException {
+ return execute(args, callPlace, null);
+ }
+
+ /**
+ * See {@link #execute(TemplateModel[], CallPlace)}; the {@link Environment} parameter can be {@code null} in
+ * this implementation.
+ */
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment envUnused) throws
+ TemplateException {
+ try {
+ return wrapper.invokeMethod(object, (Method) getMember(), unwrapArguments(args, wrapper));
+ } catch (TemplateModelException e) {
+ throw e;
+ } catch (Exception e) {
+ throw _MethodUtil.newInvocationTemplateModelException(object, getMember(), e);
+ }
+ }
+
+ @Override
+ public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+ // Required to return null! See inherited JavaDoc.
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getMember().toString();
+ }
+
+ /**
+ * Implementation of experimental interface; don't use it, no backward compatibility guarantee!
+ */
+ @Override
+ public Object[] explainTypeError(Class[] expectedClasses) {
+ final Member member = getMember();
+ if (!(member instanceof Method)) {
+ return null; // This shouldn't occur
+ }
+ Method m = (Method) member;
+
+ final Class returnType = m.getReturnType();
+ if (returnType == null || returnType == void.class || returnType == Void.class) {
+ return null; // Calling it won't help
+ }
+
+ String mName = m.getName();
+ if (mName.startsWith("get") && mName.length() > 3 && Character.isUpperCase(mName.charAt(3))
+ && (m.getParameterTypes().length == 0)) {
+ return new Object[] {
+ "Maybe using obj.something instead of obj.getSomething will yield the desired value." };
+ } else if (mName.startsWith("is") && mName.length() > 2 && Character.isUpperCase(mName.charAt(2))
+ && (m.getParameterTypes().length == 0)) {
+ return new Object[] {
+ "Maybe using obj.something instead of obj.isSomething will yield the desired value." };
+ } else {
+ return new Object[] {
+ "Maybe using obj.something(",
+ (m.getParameterTypes().length != 0 ? "params" : ""),
+ ") instead of obj.something will yield the desired value" };
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleMethod.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleMethod.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleMethod.java
index d891190..678b9ed 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleMethod.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/SimpleMethod.java
@@ -20,14 +20,12 @@ package org.apache.freemarker.core.model.impl;
import java.lang.reflect.Array;
import java.lang.reflect.Member;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
import org.apache.freemarker.core._DelayedFTLTypeDescription;
import org.apache.freemarker.core._DelayedOrdinal;
import org.apache.freemarker.core._ErrorDescriptionBuilder;
import org.apache.freemarker.core._TemplateModelException;
+import org.apache.freemarker.core.model.Constants;
import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
import org.apache.freemarker.core.model.TemplateModel;
@@ -35,7 +33,7 @@ import org.apache.freemarker.core.model.TemplateModelException;
import org.apache.freemarker.core.util._ClassUtil;
/**
- * This class is used for as a base for non-overloaded method models and for constructors.
+ * This class is used as a base for non-overloaded method models and for constructors.
* (For overloaded methods and constructors see {@link OverloadedMethods}.)
*/
class SimpleMethod {
@@ -45,101 +43,101 @@ class SimpleMethod {
+ "But consider if the Java method whose argument it will be can handle markup strings properly.";
private final Member member;
- private final Class[] argTypes;
+ private final Class<?>[] argTypes;
- protected SimpleMethod(Member member, Class[] argTypes) {
+ SimpleMethod(Member member, Class<?>[] argTypes) {
this.member = member;
this.argTypes = argTypes;
}
- Object[] unwrapArguments(List arguments, DefaultObjectWrapper wrapper) throws TemplateModelException {
- if (arguments == null) {
- arguments = Collections.EMPTY_LIST;
+ Object[] unwrapArguments(TemplateModel[] args, DefaultObjectWrapper wrapper) throws TemplateModelException {
+ if (args == null) {
+ args = Constants.EMPTY_TEMPLATE_MODEL_ARRAY;
}
boolean isVarArg = _MethodUtil.isVarargs(member);
int typesLen = argTypes.length;
if (isVarArg) {
- if (typesLen - 1 > arguments.size()) {
+ if (typesLen - 1 > args.length) {
throw new _TemplateModelException(
_MethodUtil.invocationErrorMessageStart(member),
- " takes at least ", Integer.valueOf(typesLen - 1),
+ " takes at least ", typesLen - 1,
typesLen - 1 == 1 ? " argument" : " arguments", ", but ",
- Integer.valueOf(arguments.size()), " was given.");
+ args.length, " was given.");
}
- } else if (typesLen != arguments.size()) {
+ } else if (typesLen != args.length) {
throw new _TemplateModelException(
_MethodUtil.invocationErrorMessageStart(member),
- " takes ", Integer.valueOf(typesLen), typesLen == 1 ? " argument" : " arguments", ", but ",
- Integer.valueOf(arguments.size()), " was given.");
+ " takes ", typesLen, typesLen == 1 ? " argument" : " arguments", ", but ",
+ args.length, " was given.");
}
- return unwrapArguments(arguments, argTypes, isVarArg, wrapper);
+ return unwrapArguments(args, argTypes, isVarArg, wrapper);
}
- private Object[] unwrapArguments(List args, Class[] argTypes, boolean isVarargs,
+ private Object[] unwrapArguments(TemplateModel[] args, Class<?>[] argTypes, boolean isVarargs,
DefaultObjectWrapper w)
throws TemplateModelException {
if (args == null) return null;
int typesLen = argTypes.length;
- int argsLen = args.size();
+ int argsLen = args.length;
Object[] unwrappedArgs = new Object[typesLen];
// Unwrap arguments:
- Iterator it = args.iterator();
+ int argsIdx = 0;
int normalArgCnt = isVarargs ? typesLen - 1 : typesLen;
- int argIdx = 0;
- while (argIdx < normalArgCnt) {
- Class argType = argTypes[argIdx];
- TemplateModel argVal = (TemplateModel) it.next();
+ int unwrappedArgsIdx = 0;
+ while (unwrappedArgsIdx < normalArgCnt) {
+ Class<?> argType = argTypes[unwrappedArgsIdx];
+ TemplateModel argVal = args[argsIdx++];
Object unwrappedArgVal = w.tryUnwrapTo(argVal, argType);
if (unwrappedArgVal == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
- throw createArgumentTypeMismarchException(argIdx, argVal, argType);
+ throw createArgumentTypeMismatchException(unwrappedArgsIdx, argVal, argType);
}
if (unwrappedArgVal == null && argType.isPrimitive()) {
- throw createNullToPrimitiveArgumentException(argIdx, argType);
+ throw createNullToPrimitiveArgumentException(unwrappedArgsIdx, argType);
}
- unwrappedArgs[argIdx++] = unwrappedArgVal;
+ unwrappedArgs[unwrappedArgsIdx++] = unwrappedArgVal;
}
if (isVarargs) {
// The last argType, which is the vararg type, wasn't processed yet.
- Class varargType = argTypes[typesLen - 1];
- Class varargItemType = varargType.getComponentType();
- if (!it.hasNext()) {
- unwrappedArgs[argIdx++] = Array.newInstance(varargItemType, 0);
+ Class<?> varargType = argTypes[typesLen - 1];
+ Class<?> varargItemType = varargType.getComponentType();
+ if (argsIdx >= args.length) {
+ unwrappedArgs[unwrappedArgsIdx] = Array.newInstance(varargItemType, 0);
} else {
- TemplateModel argVal = (TemplateModel) it.next();
+ TemplateModel argVal = args[argsIdx++];
Object unwrappedArgVal;
// We first try to treat the last argument as a vararg *array*.
// This is consistent to what OverloadedVarArgMethod does.
- if (argsLen - argIdx == 1
+ if (argsLen - unwrappedArgsIdx == 1
&& (unwrappedArgVal = w.tryUnwrapTo(argVal, varargType))
!= ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
// It was a vararg array.
- unwrappedArgs[argIdx++] = unwrappedArgVal;
+ unwrappedArgs[unwrappedArgsIdx] = unwrappedArgVal;
} else {
// It wasn't a vararg array, so we assume it's a vararg
// array *item*, possibly followed by further ones.
- int varargArrayLen = argsLen - argIdx;
+ int varargArrayLen = argsLen - unwrappedArgsIdx;
Object varargArray = Array.newInstance(varargItemType, varargArrayLen);
for (int varargIdx = 0; varargIdx < varargArrayLen; varargIdx++) {
- TemplateModel varargVal = (TemplateModel) (varargIdx == 0 ? argVal : it.next());
+ TemplateModel varargVal = varargIdx == 0 ? argVal : args[argsIdx++];
Object unwrappedVarargVal = w.tryUnwrapTo(varargVal, varargItemType);
if (unwrappedVarargVal == ObjectWrapperAndUnwrapper.CANT_UNWRAP_TO_TARGET_CLASS) {
- throw createArgumentTypeMismarchException(
- argIdx + varargIdx, varargVal, varargItemType);
+ throw createArgumentTypeMismatchException(
+ unwrappedArgsIdx + varargIdx, varargVal, varargItemType);
}
if (unwrappedVarargVal == null && varargItemType.isPrimitive()) {
- throw createNullToPrimitiveArgumentException(argIdx + varargIdx, varargItemType);
+ throw createNullToPrimitiveArgumentException(unwrappedArgsIdx + varargIdx, varargItemType);
}
Array.set(varargArray, varargIdx, unwrappedVarargVal);
}
- unwrappedArgs[argIdx++] = varargArray;
+ unwrappedArgs[unwrappedArgsIdx] = varargArray;
}
}
}
@@ -147,11 +145,11 @@ class SimpleMethod {
return unwrappedArgs;
}
- private TemplateModelException createArgumentTypeMismarchException(
- int argIdx, TemplateModel argVal, Class targetType) {
+ private TemplateModelException createArgumentTypeMismatchException(
+ int argIdx, TemplateModel argVal, Class<?> targetType) {
_ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
_MethodUtil.invocationErrorMessageStart(member), " couldn't be called: Can't convert the ",
- new _DelayedOrdinal(Integer.valueOf(argIdx + 1)),
+ new _DelayedOrdinal(argIdx + 1),
" argument's value to the target Java type, ", _ClassUtil.getShortClassName(targetType),
". The type of the actual value was: ", new _DelayedFTLTypeDescription(argVal));
if (argVal instanceof TemplateMarkupOutputModel && (targetType.isAssignableFrom(String.class))) {
@@ -160,10 +158,10 @@ class SimpleMethod {
return new _TemplateModelException(desc);
}
- private TemplateModelException createNullToPrimitiveArgumentException(int argIdx, Class targetType) {
+ private TemplateModelException createNullToPrimitiveArgumentException(int argIdx, Class<?> targetType) {
return new _TemplateModelException(
_MethodUtil.invocationErrorMessageStart(member), " couldn't be called: The value of the ",
- new _DelayedOrdinal(Integer.valueOf(argIdx + 1)),
+ new _DelayedOrdinal(argIdx + 1),
" argument was null, but the target Java parameter type (", _ClassUtil.getShortClassName(targetType),
") is primitive and so can't store null.");
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
index 9c4db4e..fc32348 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/StaticModel.java
@@ -27,20 +27,18 @@ import java.util.Iterator;
import java.util.Map;
import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateMethodModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Wraps the static fields and methods of a class in a
- * {@link org.apache.freemarker.core.model.TemplateHashModel}.
- * Fields are wrapped using {@link DefaultObjectWrapper#wrap(Object)}, and
- * methods are wrapped into an appropriate {@link TemplateMethodModel} instance.
- * Unfortunately, there is currently no support for bean property-style
- * calls of static methods, similar to that in {@link BeanModel}.
+ * Wraps the static fields and methods of a class in a {@link org.apache.freemarker.core.model.TemplateHashModel}.
+ * Fields are wrapped using {@link DefaultObjectWrapper#wrap(Object)}, and methods are wrapped into an appropriate
+ * {@link TemplateFunctionModel} instance. There is currently no support for bean property-style calls of static
+ * methods, similar to that in {@link BeanModel} (as it's not part for the JavaBeans specification).
*/
final class StaticModel implements TemplateHashModelEx {
@@ -167,10 +165,10 @@ final class StaticModel implements TemplateHashModelEx {
Object value = entry.getValue();
if (value instanceof Method) {
Method method = (Method) value;
- entry.setValue(new JavaMethodModel(null, method,
+ entry.setValue(new SimpleJavaMethodModel(null, method,
method.getParameterTypes(), wrapper));
} else if (value instanceof OverloadedMethods) {
- entry.setValue(new OverloadedMethodsModel(null, (OverloadedMethods) value, wrapper));
+ entry.setValue(new OverloadedJavaMethodModel(null, (OverloadedMethods) value, wrapper));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateModelListSequence.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateModelListSequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateModelListSequence.java
index 2394394..a93df33 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateModelListSequence.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/TemplateModelListSequence.java
@@ -21,26 +21,29 @@ package org.apache.freemarker.core.model.impl;
import java.util.List;
-import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
/**
* A sequence that wraps a {@link List} of {@link TemplateModel}-s. It does not copy the original
- * list. It's mostly useful when implementing {@link TemplateMethodModel}-es that collect items from other
+ * list. It's mostly useful when implementing {@link TemplateFunctionModel}-es that collect items from other
* {@link TemplateModel}-s.
*/
public class TemplateModelListSequence implements TemplateSequenceModel {
- private List/*<TemplateModel>*/ list;
+ private final List<? extends TemplateModel> list;
- public TemplateModelListSequence(List list) {
+ /**
+ * @param list The list of items; will not be copied, will not be modified.
+ */
+ public TemplateModelListSequence(List<? extends TemplateModel> list) {
this.list = list;
}
@Override
public TemplateModel get(int index) {
- return (TemplateModel) list.get(index);
+ return list.get(index);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/_MethodUtil.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/_MethodUtil.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/_MethodUtil.java
index 82da455..004ebaa 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/_MethodUtil.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/_MethodUtil.java
@@ -64,7 +64,7 @@ public final class _MethodUtil {
* </ul>
*/
// TODO Seems that we don't use the full functionality of this anymore, so we could simplify this. See usages.
- public static int isMoreOrSameSpecificParameterType(final Class specific, final Class generic, boolean bugfixed,
+ static int isMoreOrSameSpecificParameterType(final Class<?> specific, final Class<?> generic, boolean bugfixed,
int ifHigherThan) {
if (ifHigherThan >= 4) return 0;
if (generic.isAssignableFrom(specific)) {
@@ -79,7 +79,7 @@ public final class _MethodUtil {
return isWideningPrimitiveNumberConversion(specific, generic) ? 3 : 0;
} else { // => specificIsPrim && !genericIsPrim
if (bugfixed) {
- final Class specificAsBoxed = _ClassUtil.primitiveClassToBoxingClass(specific);
+ final Class<?> specificAsBoxed = _ClassUtil.primitiveClassToBoxingClass(specific);
if (specificAsBoxed == generic) {
// A primitive class is more specific than its boxing class, because it can't store null
return 2;
@@ -110,7 +110,7 @@ public final class _MethodUtil {
} // of: !generic.isAssignableFrom(specific)
}
- private static boolean isWideningPrimitiveNumberConversion(final Class source, final Class target) {
+ private static boolean isWideningPrimitiveNumberConversion(final Class<?> source, final Class<?> target) {
if (target == Short.TYPE && (source == Byte.TYPE)) {
return true;
} else if (target == Integer.TYPE &&
@@ -134,7 +134,7 @@ public final class _MethodUtil {
}
}
- private static boolean isWideningBoxedNumberConversion(final Class source, final Class target) {
+ private static boolean isWideningBoxedNumberConversion(final Class<?> source, final Class<?> target) {
if (target == Short.class && source == Byte.class) {
return true;
} else if (target == Integer.class &&
@@ -161,42 +161,42 @@ public final class _MethodUtil {
/**
* Attention, this doesn't handle primitive classes correctly, nor numerical conversions.
*/
- public static Set getAssignables(Class c1, Class c2) {
- Set s = new HashSet();
+ static Set<Class<?>> getAssignables(Class<?> c1, Class<?> c2) {
+ Set<Class<?>> s = new HashSet<>();
collectAssignables(c1, c2, s);
return s;
}
- private static void collectAssignables(Class c1, Class c2, Set s) {
+ private static void collectAssignables(Class<?> c1, Class<?> c2, Set<Class<?>> s) {
if (c1.isAssignableFrom(c2)) {
s.add(c1);
}
- Class sc = c1.getSuperclass();
+ Class<?> sc = c1.getSuperclass();
if (sc != null) {
collectAssignables(sc, c2, s);
}
- Class[] itf = c1.getInterfaces();
- for (Class anItf : itf) {
+ Class<?>[] itf = c1.getInterfaces();
+ for (Class<?> anItf : itf) {
collectAssignables(anItf, c2, s);
}
}
- public static Class[] getParameterTypes(Member member) {
+ public static Class<?>[] getParameterTypes(Member member) {
if (member instanceof Method) {
return ((Method) member).getParameterTypes();
}
- if (member instanceof Constructor) {
- return ((Constructor) member).getParameterTypes();
+ if (member instanceof Constructor<?>) {
+ return ((Constructor<?>) member).getParameterTypes();
}
throw new IllegalArgumentException("\"member\" must be Method or Constructor");
}
- public static boolean isVarargs(Member member) {
+ static boolean isVarargs(Member member) {
if (member instanceof Method) {
return ((Method) member).isVarArgs();
}
if (member instanceof Constructor) {
- return ((Constructor) member).isVarArgs();
+ return ((Constructor<?>) member).isVarArgs();
}
throw new BugException();
}
@@ -223,7 +223,7 @@ public final class _MethodUtil {
sb.append(member.getName());
sb.append('(');
- Class[] paramTypes = _MethodUtil.getParameterTypes(member);
+ Class<?>[] paramTypes = _MethodUtil.getParameterTypes(member);
for (int i = 0; i < paramTypes.length; i++) {
if (i != 0) sb.append(", ");
String paramTypeDecl = _ClassUtil.getShortClassName(paramTypes[i]);
@@ -239,7 +239,7 @@ public final class _MethodUtil {
return sb.toString();
}
- public static Object[] invocationErrorMessageStart(Member member) {
+ static Object[] invocationErrorMessageStart(Member member) {
return invocationErrorMessageStart(member, member instanceof Constructor);
}
@@ -247,7 +247,7 @@ public final class _MethodUtil {
return new Object[] { "Java ", isConstructor ? "constructor " : "method ", new _DelayedJQuote(member) };
}
- public static TemplateModelException newInvocationTemplateModelException(Object object, Member member, Throwable e) {
+ static TemplateModelException newInvocationTemplateModelException(Object object, Member member, Throwable e) {
return newInvocationTemplateModelException(
object,
member,
@@ -256,7 +256,7 @@ public final class _MethodUtil {
e);
}
- public static TemplateModelException newInvocationTemplateModelException(Object object, CallableMemberDescriptor callableMemberDescriptor, Throwable e) {
+ static TemplateModelException newInvocationTemplateModelException(Object object, CallableMemberDescriptor callableMemberDescriptor, Throwable e) {
return newInvocationTemplateModelException(
object,
new _DelayedConversionToString(callableMemberDescriptor) {
@@ -294,7 +294,7 @@ public final class _MethodUtil {
* Extracts the JavaBeans property from a reader method name, or returns {@code null} if the method name doesn't
* look like a reader method name.
*/
- public static String getBeanPropertyNameFromReaderMethodName(String name, Class<?> returnType) {
+ static String getBeanPropertyNameFromReaderMethodName(String name, Class<?> returnType) {
int start;
if (name.startsWith("get")) {
start = 3;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
index 2923647..7c58284 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
@@ -34,7 +34,6 @@ import org.apache.freemarker.core.model.TemplateFunctionModel;
import org.apache.freemarker.core.model.TemplateHashModel;
import org.apache.freemarker.core.model.TemplateHashModelEx;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelIterator;
import org.apache.freemarker.core.model.TemplateNodeModel;
@@ -45,6 +44,7 @@ import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.WrapperTemplateModel;
import org.apache.freemarker.core.model.impl.BeanAndStringModel;
import org.apache.freemarker.core.model.impl.BeanModel;
+import org.apache.freemarker.core.model.impl.JavaMethodModel;
/**
* Static utility methods that perform tasks specific to the FreeMarker Template Language (FTL).
@@ -760,7 +760,7 @@ public final class FTLUtil {
}
if (callable instanceof TemplateFunctionModel) {
- String f = "function"; // TODO [FM3][CF] Should say "method" sometimes
+ String f = callable instanceof JavaMethodModel ? "method" : "function";
result = d == null ? f : d + "+" + f;
}
@@ -799,7 +799,8 @@ public final class FTLUtil {
appendTypeName(sb, typeNamesAppended, _CoreAPI.isMacro(cl) ? "macro" : "directive");
}
if (TemplateFunctionModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "function"); // TODO [FM3][CF] should say "method" sometimes
+ appendTypeName(sb, typeNamesAppended,
+ JavaMethodModel.class.isAssignableFrom(cl) ? "method" : "function");
}
}
@@ -812,10 +813,6 @@ public final class FTLUtil {
appendTypeName(sb, typeNamesAppended, "iterator");
}
- if (TemplateMethodModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "method");
- }
-
if (Environment.Namespace.class.isAssignableFrom(cl)) {
appendTypeName(sb, typeNamesAppended, "namespace");
} else if (TemplateHashModelEx.class.isAssignableFrom(cl)) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8d5263f2/freemarker-core/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/javacc/FTL.jj b/freemarker-core/src/main/javacc/FTL.jj
index 5d1b354..4201d84 100644
--- a/freemarker-core/src/main/javacc/FTL.jj
+++ b/freemarker-core/src/main/javacc/FTL.jj
@@ -2040,7 +2040,7 @@ ASTExpression DynamicKey(ASTExpression exp) :
/**
* production for an arglist part of a method invocation.
*/
-ASTExpMethodCall MethodArgs(ASTExpression exp) :
+ASTExpFunctionCall MethodArgs(ASTExpression exp) :
{
ArrayList args = new ArrayList();
Token end;
@@ -2051,7 +2051,7 @@ ASTExpMethodCall MethodArgs(ASTExpression exp) :
end = <CLOSE_PAREN>
{
args.trimToSize();
- ASTExpMethodCall result = new ASTExpMethodCall(exp, args);
+ ASTExpFunctionCall result = new ASTExpFunctionCall(exp, args);
result.setLocation(template, exp, end);
return result;
}