You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2018/10/17 11:42:10 UTC
svn commit: r1844087 - in
/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src:
main/java/org/apache/velocity/util/introspection/
main/resources/org/apache/velocity/runtime/defaults/
test/java/org/apache/velocity/test/util/introspection/
Author: cbrisson
Date: Wed Oct 17 11:42:10 2018
New Revision: 1844087
URL: http://svn.apache.org/viewvc?rev=1844087&view=rev
Log:
[VELOCITY-892] Handling conversions towards Type (work in progress)
Added:
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandler.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java
Removed:
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandlerImpl.java
Modified:
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassMap.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandler.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Introspector.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties
velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassMap.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassMap.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassMap.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassMap.java Wed Oct 17 11:42:10 2018
@@ -73,7 +73,7 @@ public class ClassMap
* @param conversionHandler conversion handler
* @since 2.0
*/
- public ClassMap(final Class clazz, final Logger log, final ConversionHandler conversionHandler)
+ public ClassMap(final Class clazz, final Logger log, final TypeConversionHandler conversionHandler)
{
this.clazz = clazz;
this.log = log;
@@ -121,7 +121,7 @@ public class ClassMap
* are taken from all the public methods
* that our class, its parents and their implemented interfaces provide.
*/
- private MethodCache createMethodCache(ConversionHandler conversionHandler)
+ private MethodCache createMethodCache(TypeConversionHandler conversionHandler)
{
MethodCache methodCache = new MethodCache(log, conversionHandler);
//
@@ -231,7 +231,7 @@ public class ClassMap
/** Map of methods that are searchable according to method parameters to find a match */
private final MethodMap methodMap;
- private MethodCache(Logger log, ConversionHandler conversionHandler)
+ private MethodCache(Logger log, TypeConversionHandler conversionHandler)
{
this.log = log;
methodMap = new MethodMap(conversionHandler);
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandler.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandler.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandler.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ConversionHandler.java Wed Oct 17 11:42:10 2018
@@ -27,13 +27,17 @@ package org.apache.velocity.util.introsp
*
* @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
* @version $Id: ConversionHandler.java $
+ * @deprecated use {@link TypeConversionHandler}
+ * @see TypeConversionHandler
* @since 2.0
*/
+@Deprecated
public interface ConversionHandler
{
/**
* Check to see if the conversion can be done using an explicit conversion
+ *
* @param formal expected formal type
* @param actual provided argument type
* @return null if no conversion is needed, or the appropriate Converter object
@@ -55,10 +59,11 @@ public interface ConversionHandler
/**
* Add the given converter to the handler. Implementation should be thread-safe.
*
- * @param formal expected formal type
- * @param actual provided argument type
+ * @param formal expected formal type
+ * @param actual provided argument type
* @param converter converter
* @since 2.0
*/
void addConverter(Class formal, Class actual, Converter converter);
}
+
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectionUtils.java Wed Oct 17 11:42:10 2018
@@ -19,6 +19,9 @@ package org.apache.velocity.util.introsp
* under the License.
*/
+import org.apache.commons.lang3.reflect.TypeUtils;
+
+import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -87,7 +90,6 @@ public class IntrospectionUtils
*
*/
-
/**
* Determines whether a type represented by a class object is
* convertible to another type represented by a class object using a
@@ -108,92 +110,100 @@ public class IntrospectionUtils
* type or an object type of a primitive type that can be converted to
* the formal type.
*/
- public static boolean isMethodInvocationConvertible(Class formal,
+ public static boolean isMethodInvocationConvertible(Type formal,
Class actual,
boolean possibleVarArg)
{
- /* if it's a null, it means the arg was null */
- if (actual == null)
+ if (formal instanceof Class)
{
- return !formal.isPrimitive();
- }
+ Class formalClass = (Class)formal;
+ /* if it's a null, it means the arg was null */
+ if (actual == null)
+ {
+ return !formalClass.isPrimitive();
+ }
- /* Check for identity or widening reference conversion */
- if (formal.isAssignableFrom(actual))
- {
- return true;
- }
+ /* Check for identity or widening reference conversion */
+ if (formalClass.isAssignableFrom(actual))
+ {
+ return true;
+ }
- /* 2.0: Since MethodMap's comparison functions now use this method with potentially reversed arguments order,
- * actual can be a primitive type. */
+ /* 2.0: Since MethodMap's comparison functions now use this method with potentially reversed arguments order,
+ * actual can be a primitive type. */
- /* Check for boxing */
- if (!formal.isPrimitive() && actual.isPrimitive())
- {
- Class boxed = boxingMap.get(actual);
- if (boxed != null && boxed == formal || formal.isAssignableFrom(boxed)) return true;
- }
+ /* Check for boxing */
+ if (!formalClass.isPrimitive() && actual.isPrimitive())
+ {
+ Class boxed = boxingMap.get(actual);
+ if (boxed != null && boxed == formalClass || formalClass.isAssignableFrom(boxed)) return true;
+ }
- if (formal.isPrimitive())
- {
- if (actual.isPrimitive())
+ if (formalClass.isPrimitive())
{
- /* check for widening primitive conversion */
- if (formal == Short.TYPE && actual == Byte.TYPE)
- return true;
- if (formal == Integer.TYPE && (
+ if (actual.isPrimitive())
+ {
+ /* check for widening primitive conversion */
+ if (formalClass == Short.TYPE && actual == Byte.TYPE)
+ return true;
+ if (formalClass == Integer.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE))
- return true;
- if (formal == Long.TYPE && (
+ return true;
+ if (formalClass == Long.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE))
- return true;
- if (formal == Float.TYPE && (
+ return true;
+ if (formalClass == Float.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE ||
- actual == Long.TYPE))
- return true;
- if (formal == Double.TYPE && (
+ actual == Long.TYPE))
+ return true;
+ if (formalClass == Double.TYPE && (
actual == Byte.TYPE || actual == Short.TYPE || actual == Integer.TYPE ||
- actual == Long.TYPE || actual == Float.TYPE))
- return true;
- }
- else
- {
- /* Check for unboxing with widening primitive conversion. */
- if (formal == Boolean.TYPE && actual == Boolean.class)
- return true;
- if (formal == Character.TYPE && actual == Character.class)
- return true;
- if (formal == Byte.TYPE && actual == Byte.class)
- return true;
- if (formal == Short.TYPE && (actual == Short.class || actual == Byte.class))
- return true;
- if (formal == Integer.TYPE && (actual == Integer.class || actual == Short.class ||
+ actual == Long.TYPE || actual == Float.TYPE))
+ return true;
+ } else
+ {
+ /* Check for unboxing with widening primitive conversion. */
+ if (formalClass == Boolean.TYPE && actual == Boolean.class)
+ return true;
+ if (formalClass == Character.TYPE && actual == Character.class)
+ return true;
+ if (formalClass == Byte.TYPE && actual == Byte.class)
+ return true;
+ if (formalClass == Short.TYPE && (actual == Short.class || actual == Byte.class))
+ return true;
+ if (formalClass == Integer.TYPE && (actual == Integer.class || actual == Short.class ||
actual == Byte.class))
- return true;
- if (formal == Long.TYPE && (actual == Long.class || actual == Integer.class ||
+ return true;
+ if (formalClass == Long.TYPE && (actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
- return true;
- if (formal == Float.TYPE && (actual == Float.class || actual == Long.class ||
+ return true;
+ if (formalClass == Float.TYPE && (actual == Float.class || actual == Long.class ||
actual == Integer.class || actual == Short.class || actual == Byte.class))
- return true;
- if (formal == Double.TYPE && (actual == Double.class || actual == Float.class ||
+ return true;
+ if (formalClass == Double.TYPE && (actual == Double.class || actual == Float.class ||
actual == Long.class || actual == Integer.class || actual == Short.class ||
actual == Byte.class))
- return true;
+ return true;
+ }
}
- }
- /* Check for vararg conversion. */
- if (possibleVarArg && formal.isArray())
- {
- if (actual.isArray())
+ /* Check for vararg conversion. */
+ if (possibleVarArg && formalClass.isArray())
{
- actual = actual.getComponentType();
+ if (actual.isArray())
+ {
+ actual = actual.getComponentType();
+ }
+ return isMethodInvocationConvertible(formalClass.getComponentType(),
+ actual, false);
}
- return isMethodInvocationConvertible(formal.getComponentType(),
- actual, false);
+ return false;
+ }
+ else
+ {
+ // no distinction between strict and implicit, not a big deal in this case
+ return TypeUtils.isAssignable(actual, formal);
}
- return false;
}
/**
@@ -212,55 +222,64 @@ public class IntrospectionUtils
* or formal and actual are both primitive types and actual can be
* subject to widening conversion to formal.
*/
- public static boolean isStrictMethodInvocationConvertible(Class formal,
+ public static boolean isStrictMethodInvocationConvertible(Type formal,
Class actual,
boolean possibleVarArg)
{
- /* Check for nullity */
- if (actual == null)
- {
- return !formal.isPrimitive();
- }
-
- /* Check for identity or widening reference conversion */
- if(formal.isAssignableFrom(actual))
+ if (formal instanceof Class)
{
- return true;
- }
+ Class formalClass = (Class) formal;
+ /* Check for nullity */
+ if (actual == null)
+ {
+ return !formalClass.isPrimitive();
+ }
- /* Check for widening primitive conversion. */
- if(formal.isPrimitive())
- {
- if(formal == Short.TYPE && (actual == Byte.TYPE))
- return true;
- if(formal == Integer.TYPE &&
- (actual == Short.TYPE || actual == Byte.TYPE))
- return true;
- if(formal == Long.TYPE &&
- (actual == Integer.TYPE || actual == Short.TYPE ||
- actual == Byte.TYPE))
- return true;
- if(formal == Float.TYPE &&
- (actual == Long.TYPE || actual == Integer.TYPE ||
- actual == Short.TYPE || actual == Byte.TYPE))
- return true;
- if(formal == Double.TYPE &&
- (actual == Float.TYPE || actual == Long.TYPE ||
- actual == Integer.TYPE || actual == Short.TYPE ||
- actual == Byte.TYPE))
+ /* Check for identity or widening reference conversion */
+ if (formalClass.isAssignableFrom(actual))
+ {
return true;
- }
+ }
- /* Check for vararg conversion. */
- if (possibleVarArg && formal.isArray())
- {
- if (actual.isArray())
+ /* Check for widening primitive conversion. */
+ if (formalClass.isPrimitive())
+ {
+ if (formal == Short.TYPE && (actual == Byte.TYPE))
+ return true;
+ if (formal == Integer.TYPE &&
+ (actual == Short.TYPE || actual == Byte.TYPE))
+ return true;
+ if (formal == Long.TYPE &&
+ (actual == Integer.TYPE || actual == Short.TYPE ||
+ actual == Byte.TYPE))
+ return true;
+ if (formal == Float.TYPE &&
+ (actual == Long.TYPE || actual == Integer.TYPE ||
+ actual == Short.TYPE || actual == Byte.TYPE))
+ return true;
+ if (formal == Double.TYPE &&
+ (actual == Float.TYPE || actual == Long.TYPE ||
+ actual == Integer.TYPE || actual == Short.TYPE ||
+ actual == Byte.TYPE))
+ return true;
+ }
+
+ /* Check for vararg conversion. */
+ if (possibleVarArg && formalClass.isArray())
{
- actual = actual.getComponentType();
+ if (actual.isArray())
+ {
+ actual = actual.getComponentType();
+ }
+ return isStrictMethodInvocationConvertible(formalClass.getComponentType(),
+ actual, false);
}
- return isStrictMethodInvocationConvertible(formal.getComponentType(),
- actual, false);
+ return false;
+ }
+ else
+ {
+ // no distinction between strict and implicit, not a big deal in this case
+ return TypeUtils.isAssignable(actual, formal);
}
- return false;
}
}
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Introspector.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Introspector.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Introspector.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/Introspector.java Wed Oct 17 11:42:10 2018
@@ -68,7 +68,7 @@ public class Introspector extends Intros
* @param conversionHandler conversion handler
* @since 2.0
*/
- public Introspector(final Logger log, ConversionHandler conversionHandler)
+ public Introspector(final Logger log, TypeConversionHandler conversionHandler)
{
super(log, conversionHandler);
}
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java Wed Oct 17 11:42:10 2018
@@ -62,17 +62,13 @@ public abstract class IntrospectorBase
/** The Introspector Cache */
private final IntrospectorCache introspectorCache;
- /** The Conversion handler */
- private final ConversionHandler conversionHandler;
-
/**
* C'tor.
*/
- protected IntrospectorBase(final Logger log, final ConversionHandler conversionHandler)
+ protected IntrospectorBase(final Logger log, final TypeConversionHandler conversionHandler)
{
this.log = log;
introspectorCache = new IntrospectorCache(log, conversionHandler);
- this.conversionHandler = conversionHandler;
}
/**
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java Wed Oct 17 11:42:10 2018
@@ -68,12 +68,12 @@ public final class IntrospectorCache
/**
* Conversion handler
*/
- private final ConversionHandler conversionHandler;
+ private final TypeConversionHandler conversionHandler;
/**
* C'tor
*/
- public IntrospectorCache(final Logger log, final ConversionHandler conversionHandler)
+ public IntrospectorCache(final Logger log, final TypeConversionHandler conversionHandler)
{
this.log = log;
this.conversionHandler = conversionHandler;
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/MethodMap.java Wed Oct 17 11:42:10 2018
@@ -19,9 +19,11 @@ package org.apache.velocity.util.introsp
* under the License.
*/
+import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.velocity.exception.VelocityException;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
@@ -54,7 +56,7 @@ public class MethodMap
private static final int IMPLCITLY_CONVERTIBLE = 2;
private static final int STRICTLY_CONVERTIBLE = 3;
- ConversionHandler conversionHandler;
+ TypeConversionHandler conversionHandler;
/**
* Default constructor
@@ -69,7 +71,7 @@ public class MethodMap
* @param conversionHandler conversion handler
* @since 2.0
*/
- public MethodMap(ConversionHandler conversionHandler)
+ public MethodMap(TypeConversionHandler conversionHandler)
{
this.conversionHandler = conversionHandler;
}
@@ -173,7 +175,7 @@ public class MethodMap
Method method;
/* cache arguments classes array */
- Class[] methodTypes;
+ Type[] methodTypes;
/* specificity: how does the best match compare to provided arguments
* one one LESS_SPECIFIC, MORE_SPECIFIC or INCOMPARABLE */
@@ -190,9 +192,9 @@ public class MethodMap
{
this.method = method;
this.applicability = applicability;
- this.methodTypes = method.getParameterTypes();
+ this.methodTypes = method.getGenericParameterTypes();
this.specificity = compare(methodTypes, unboxedArgs);
- this.varargs = methodTypes.length > 0 && methodTypes[methodTypes.length - 1].isArray();
+ this.varargs = methodTypes.length > 0 && (methodTypes[methodTypes.length - 1] instanceof Class) && ((Class)methodTypes[methodTypes.length - 1]).isArray();
}
}
@@ -322,74 +324,74 @@ public class MethodMap
/**
* Determines which method signature (represented by a class array) is more
* specific. This defines a partial ordering on the method signatures.
- * @param c1 first signature to compare
- * @param c2 second signature to compare
+ * @param t1 first signature to compare
+ * @param t2 second signature to compare
* @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
* c1 is less specific than c2, INCOMPARABLE if they are incomparable.
*/
- private int compare(Class[] c1, Class[] c2)
+ private int compare(Type[] t1, Type[] t2)
{
- boolean c1IsVararag = false;
- boolean c2IsVararag = false;
+ boolean t1IsVararag = false;
+ boolean t2IsVararag = false;
boolean fixedLengths = false;
// compare lengths to handle comparisons where the size of the arrays
// doesn't match, but the methods are both applicable due to the fact
// that one is a varargs method
- if (c1.length > c2.length)
+ if (t1.length > t2.length)
{
- int l2 = c2.length;
+ int l2 = t2.length;
if (l2 == 0)
{
return MORE_SPECIFIC;
}
- c2 = Arrays.copyOf(c2, c1.length);
- Class itemClass = c2[l2 - 1].getComponentType();
+ t2 = Arrays.copyOf(t2, t1.length);
+ Type itemType = t2[l2 - 1] instanceof Class ? ((Class)t2[l2 - 1]).getComponentType() : null;
/* if item class is null, then it implies the vaarg is #1
* (and receives an empty array)
*/
- if (itemClass == null)
+ if (itemType == null)
{
/* by construct, we have c1.length = l2 + 1 */
- c1IsVararag = true;
- c2[c1.length - 1] = null;
+ t1IsVararag = true;
+ t2[t1.length - 1] = null;
}
else
{
- c2IsVararag = true;
- for (int i = l2 - 1; i < c1.length; ++i)
+ t2IsVararag = true;
+ for (int i = l2 - 1; i < t1.length; ++i)
{
/* also overwrite the vaargs itself */
- c2[i] = itemClass;
+ t2[i] = itemType;
}
}
fixedLengths = true;
}
- else if (c2.length > c1.length)
+ else if (t2.length > t1.length)
{
- int l1 = c1.length;
+ int l1 = t1.length;
if (l1 == 0)
{
return LESS_SPECIFIC;
}
- c1 = Arrays.copyOf(c1, c2.length);
- Class itemClass = c1[l1 - 1].getComponentType();
+ t1 = Arrays.copyOf(t1, t2.length);
+ Type itemType = t1[l1 - 1] instanceof Class ? ((Class)t1[l1 - 1]).getComponentType() : null;
/* if item class is null, then it implies the vaarg is #2
* (and receives an empty array)
*/
- if (itemClass == null)
+ if (itemType == null)
{
/* by construct, we have c2.length = l1 + 1 */
- c2IsVararag = true;
- c1[c2.length - 1] = null;
+ t2IsVararag = true;
+ t1[t2.length - 1] = null;
}
else
{
- c1IsVararag = true;
- for (int i = l1 - 1; i < c2.length; ++i)
+ t1IsVararag = true;
+ for (int i = l1 - 1; i < t2.length; ++i)
{
/* also overwrite the vaargs itself */
- c1[i] = itemClass;
+ t1[i] = itemType;
}
}
fixedLengths = true;
@@ -398,52 +400,72 @@ public class MethodMap
/* ok, move on and compare those of equal lengths */
int fromC1toC2 = STRICTLY_CONVERTIBLE;
int fromC2toC1 = STRICTLY_CONVERTIBLE;
- for(int i = 0; i < c1.length; ++i)
+ for(int i = 0; i < t1.length; ++i)
{
- boolean last = !fixedLengths && (i == c1.length - 1);
- if (c1[i] != c2[i])
+ boolean last = !fixedLengths && (i == t1.length - 1);
+ if (t1[i] != t2[i])
{
- if (c1[i] == null)
+ if (t1[i] == null)
{
fromC2toC1 = NOT_CONVERTIBLE;
- if (c2[i].isPrimitive())
+ if ((t2[i] instanceof Class) && ((Class)t2[i]).isPrimitive())
{
fromC1toC2 = NOT_CONVERTIBLE;
}
}
- else if (c2[i] == null)
+ else if (t2[i] == null)
{
fromC1toC2 = NOT_CONVERTIBLE;
- if (c1[i].isPrimitive())
+ if ((t1[i] instanceof Class) && ((Class)t1[i]).isPrimitive())
{
fromC2toC1 = NOT_CONVERTIBLE;
}
}
else
{
- switch (fromC1toC2)
+ if (t1[i] instanceof Class)
{
- case STRICTLY_CONVERTIBLE:
- if (isStrictConvertible(c2[i], c1[i], last)) break;
- fromC1toC2 = IMPLCITLY_CONVERTIBLE;
- case IMPLCITLY_CONVERTIBLE:
- if (isConvertible(c2[i], c1[i], last)) break;
- fromC1toC2 = EXPLICITLY_CONVERTIBLE;
- case EXPLICITLY_CONVERTIBLE:
- if (isExplicitlyConvertible(c2[i], c1[i], last)) break;
- fromC1toC2 = NOT_CONVERTIBLE;
- }
- switch (fromC2toC1)
- {
- case STRICTLY_CONVERTIBLE:
- if (isStrictConvertible(c1[i], c2[i], last)) break;
- fromC2toC1 = IMPLCITLY_CONVERTIBLE;
- case IMPLCITLY_CONVERTIBLE:
- if (isConvertible(c1[i], c2[i], last)) break;
- fromC2toC1 = EXPLICITLY_CONVERTIBLE;
- case EXPLICITLY_CONVERTIBLE:
- if (isExplicitlyConvertible(c1[i], c2[i], last)) break;
- fromC2toC1 = NOT_CONVERTIBLE;
+ Class c1 = (Class)t1[i];
+ switch (fromC1toC2)
+ {
+ case STRICTLY_CONVERTIBLE:
+ if (isStrictConvertible(t2[i], c1, last)) break;
+ fromC1toC2 = IMPLCITLY_CONVERTIBLE;
+ case IMPLCITLY_CONVERTIBLE:
+ if (isConvertible(t2[i], c1, last)) break;
+ fromC1toC2 = EXPLICITLY_CONVERTIBLE;
+ case EXPLICITLY_CONVERTIBLE:
+ if (isExplicitlyConvertible(t2[i], c1, last)) break;
+ fromC1toC2 = NOT_CONVERTIBLE;
+ }
+ }
+ else if (fromC1toC2 > NOT_CONVERTIBLE)
+ {
+ fromC1toC2 = TypeUtils.isAssignable(t1[i], t2[i]) ?
+ Math.min(fromC1toC2, IMPLCITLY_CONVERTIBLE) :
+ NOT_CONVERTIBLE;
+ }
+ if (t2[i] instanceof Class)
+ {
+ Class c2 = (Class)t2[i];
+ switch (fromC2toC1)
+ {
+ case STRICTLY_CONVERTIBLE:
+ if (isStrictConvertible(t1[i], c2, last)) break;
+ fromC2toC1 = IMPLCITLY_CONVERTIBLE;
+ case IMPLCITLY_CONVERTIBLE:
+ if (isConvertible(t1[i], c2, last)) break;
+ fromC2toC1 = EXPLICITLY_CONVERTIBLE;
+ case EXPLICITLY_CONVERTIBLE:
+ if (isExplicitlyConvertible(t1[i], c2, last)) break;
+ fromC2toC1 = NOT_CONVERTIBLE;
+ }
+ }
+ else if (fromC2toC1 > NOT_CONVERTIBLE)
+ {
+ fromC2toC1 = TypeUtils.isAssignable(t2[i], t1[i]) ?
+ Math.min(fromC2toC1, IMPLCITLY_CONVERTIBLE) :
+ NOT_CONVERTIBLE;
}
}
}
@@ -472,8 +494,8 @@ public class MethodMap
* If one method accepts varargs and the other does not,
* call the non-vararg one more specific.
*/
- boolean last1Array = c1IsVararag || !fixedLengths && c1[c1.length - 1].isArray();
- boolean last2Array = c2IsVararag || !fixedLengths && c2[c2.length - 1].isArray();
+ boolean last1Array = t1IsVararag || !fixedLengths && (t1[t1.length - 1] instanceof Class) && ((Class)t1[t1.length - 1]).isArray();
+ boolean last2Array = t2IsVararag || !fixedLengths && (t2[t2.length - 1] instanceof Class) && ((Class)t2[t2.length - 1]).isArray();
if (last1Array && !last2Array)
{
return LESS_SPECIFIC;
@@ -499,14 +521,15 @@ public class MethodMap
*/
private int getApplicability(Method method, Class[] classes)
{
- Class[] methodArgs = method.getParameterTypes();
+ Type[] methodArgs = method.getGenericParameterTypes();
int ret = STRICTLY_CONVERTIBLE;
if (methodArgs.length > classes.length)
{
// if there's just one more methodArg than class arg
// and the last methodArg is an array, then treat it as a vararg
if (methodArgs.length == classes.length + 1 &&
- methodArgs[methodArgs.length - 1].isArray())
+ (methodArgs[methodArgs.length - 1] instanceof Class) &&
+ ((Class)methodArgs[methodArgs.length - 1]).isArray())
{
// all the args preceding the vararg must match
for (int i = 0; i < classes.length; i++)
@@ -541,13 +564,14 @@ public class MethodMap
// (e.g. String when the method is expecting String...)
for(int i = 0; i < classes.length; ++i)
{
- if (!isStrictConvertible(methodArgs[i], classes[i], i == classes.length - 1 && methodArgs[i].isArray()))
+ boolean possibleVararg = i == classes.length - 1 && (methodArgs[i] instanceof Class) && ((Class)methodArgs[i]).isArray();
+ if (!isStrictConvertible(methodArgs[i], classes[i], possibleVararg))
{
- if (isConvertible(methodArgs[i], classes[i], i == classes.length - 1 && methodArgs[i].isArray()))
+ if (isConvertible(methodArgs[i], classes[i], possibleVararg))
{
ret = Math.min(ret, IMPLCITLY_CONVERTIBLE);
}
- else if (isExplicitlyConvertible(methodArgs[i], classes[i], i == classes.length - 1 && methodArgs[i].isArray()))
+ else if (isExplicitlyConvertible(methodArgs[i], classes[i], possibleVararg))
{
ret = Math.min(ret, EXPLICITLY_CONVERTIBLE);
}
@@ -562,8 +586,8 @@ public class MethodMap
else if (methodArgs.length > 0) // more arguments given than the method accepts; check for varargs
{
// check that the last methodArg is an array
- Class lastarg = methodArgs[methodArgs.length - 1];
- if (!lastarg.isArray())
+ Type lastarg = methodArgs[methodArgs.length - 1];
+ if (!(lastarg instanceof Class) || !((Class)lastarg).isArray())
{
return NOT_CONVERTIBLE;
}
@@ -589,7 +613,7 @@ public class MethodMap
}
// check that all remaining arguments are convertible to the vararg type
- Class vararg = lastarg.getComponentType();
+ Class vararg = ((Class)lastarg).getComponentType();
for (int i = methodArgs.length - 1; i < classes.length; ++i)
{
if (!isStrictConvertible(vararg, classes[i], false))
@@ -621,7 +645,7 @@ public class MethodMap
* @param possibleVarArg
* @return convertible
*/
- private boolean isConvertible(Class formal, Class actual, boolean possibleVarArg)
+ private boolean isConvertible(Type formal, Class actual, boolean possibleVarArg)
{
return IntrospectionUtils.
isMethodInvocationConvertible(formal, actual, possibleVarArg);
@@ -636,7 +660,7 @@ public class MethodMap
* @param possibleVarArg
* @return convertible
*/
- private static boolean isStrictConvertible(Class formal, Class actual, boolean possibleVarArg)
+ private static boolean isStrictConvertible(Type formal, Class actual, boolean possibleVarArg)
{
return IntrospectionUtils.
isStrictMethodInvocationConvertible(formal, actual, possibleVarArg);
@@ -650,7 +674,7 @@ public class MethodMap
* @param possibleVarArg
* @return
*/
- private boolean isExplicitlyConvertible(Class formal, Class actual, boolean possibleVarArg)
+ private boolean isExplicitlyConvertible(Type formal, Class actual, boolean possibleVarArg)
{
return conversionHandler != null && conversionHandler.isExplicitlyConvertible(formal, actual, possibleVarArg);
}
Added: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandler.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandler.java?rev=1844087&view=auto
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandler.java (added)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandler.java Wed Oct 17 11:42:10 2018
@@ -0,0 +1,67 @@
+package org.apache.velocity.util.introspection;
+
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Type;
+
+/**
+ * A conversion handler adds admissible conversions between Java types whenever Velocity introspection has to map
+ * VTL methods and property accessors to Java methods.
+ * Both methods must be consistent: <code>getNeededConverter</code> must not return <code>null</code> whenever
+ * <code>isExplicitlyConvertible</code> returned true with the same arguments.
+ *
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ * @version $Id: ConversionHandler.java $
+ * @since 2.1
+ */
+
+public interface TypeConversionHandler
+{
+ /**
+ * Check to see if the conversion can be done using an explicit conversion
+ * @param formal expected formal type
+ * @param actual provided argument type
+ * @return null if no conversion is needed, or the appropriate Converter object
+ * @since 2.1
+ */
+ boolean isExplicitlyConvertible(Type formal, Class actual, boolean possibleVarArg);
+
+ /**
+ * Returns the appropriate Converter object needed for an explicit conversion
+ * Returns null if no conversion is needed.
+ *
+ * @param formal expected formal type
+ * @param actual provided argument type
+ * @return null if no conversion is needed, or the appropriate Converter object
+ * @since 2.1
+ */
+ Converter getNeededConverter(Type formal, Class actual);
+
+ /**
+ * Add the given converter to the handler. Implementation should be thread-safe.
+ *
+ * @param formal expected formal type
+ * @param actual provided argument type
+ * @param converter converter
+ * @since 2.1
+ */
+ void addConverter(Type formal, Class actual, Converter converter);
+
+}
Added: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java?rev=1844087&view=auto
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java (added)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/TypeConversionHandlerImpl.java Wed Oct 17 11:42:10 2018
@@ -0,0 +1,618 @@
+package org.apache.velocity.util.introspection;
+
+/*
+ * 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.
+ */
+
+import org.apache.velocity.util.Pair;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A conversion handler adds admissible conversions between Java types whenever Velocity introspection has to map
+ * VTL methods and property accessors to Java methods. This implementation is the default Conversion Handler
+ * for Velocity.
+ *
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ * @version $Id: TypeConversionHandlerImpl.java $
+ * @since 2.0
+ */
+
+public class TypeConversionHandlerImpl implements TypeConversionHandler
+{
+ /**
+ * standard narrowing and string parsing conversions.
+ */
+ static Map<Pair<? extends Type, ? extends Class>, Converter> standardConverterMap;
+
+ /**
+ * basic toString converter
+ */
+ static Converter toString;
+
+ /**
+ * cache miss converter
+ */
+ static Converter cacheMiss;
+
+ /**
+ * min/max byte/short/int values as long
+ */
+ static final long minByte = Byte.MIN_VALUE, maxByte = Byte.MAX_VALUE,
+ minShort = Short.MIN_VALUE, maxShort = Short.MAX_VALUE,
+ minInt = Integer.MIN_VALUE, maxInt = Integer.MAX_VALUE;
+
+ /**
+ * min/max long values as double
+ */
+ static final double minLong = Long.MIN_VALUE, maxLong = Long.MAX_VALUE;
+
+ /**
+ * a converters cache map, initialized with the standard narrowing and string parsing conversions.
+ */
+ Map<Pair<? extends Type, ? extends Class>, Converter> converterCacheMap;
+
+ static
+ {
+ standardConverterMap = new HashMap<>();
+
+ cacheMiss = new Converter<Object>()
+ {
+ @Override
+ public Object convert(Object o)
+ {
+ return o;
+ }
+ };
+
+ /* number -> boolean */
+ Converter<Boolean> numberToBool = new Converter<Boolean>()
+ {
+ @Override
+ public Boolean convert(Object o)
+ {
+ return o == null ? null : ((Number) o).intValue() != 0;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Boolean.class, Byte.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Short.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Integer.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Long.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Float.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Double.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Number.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Byte.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Short.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Integer.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Long.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Float.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.class, Double.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Byte.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Short.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Integer.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Long.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Float.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Double.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Number.class), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Byte.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Short.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Integer.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Long.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Float.TYPE), numberToBool);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Double.TYPE), numberToBool);
+
+ /* character -> boolean */
+ Converter<Boolean> charToBoolean = new Converter<Boolean>()
+ {
+ @Override
+ public Boolean convert(Object o)
+ {
+ return o == null ? null : (Character) o != 0;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Boolean.class, Character.class), charToBoolean);
+ standardConverterMap.put(new Pair<>(Boolean.class, Character.TYPE), charToBoolean);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Character.class), charToBoolean);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, Character.TYPE), charToBoolean);
+
+ /* string -> boolean */
+ Converter<Boolean> stringToBoolean = new Converter<Boolean>()
+ {
+ @Override
+ public Boolean convert(Object o)
+ {
+ return Boolean.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Boolean.class, String.class), stringToBoolean);
+ standardConverterMap.put(new Pair<>(Boolean.TYPE, String.class), stringToBoolean);
+
+ /* narrowing towards byte */
+ Converter<Byte> narrowingToByte = new Converter<Byte>()
+ {
+ @Override
+ public Byte convert(Object o)
+ {
+ if (o == null) return null;
+ long l = ((Number)o).longValue();
+ if (l < minByte || l > maxByte)
+ {
+ throw new NumberFormatException("value out of range for byte type: " + l);
+ }
+ return ((Number) o).byteValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Byte.class, Short.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Integer.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Long.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Float.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Double.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Number.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Short.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Integer.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Long.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Float.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Double.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Short.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Integer.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Long.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Float.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Double.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Number.class), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Short.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Integer.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Long.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Float.TYPE), narrowingToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Double.TYPE), narrowingToByte);
+
+ /* string to byte */
+ Converter<Byte> stringToByte = new Converter<Byte>()
+ {
+ @Override
+ public Byte convert(Object o)
+ {
+ return Byte.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Byte.class, String.class), stringToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, String.class), stringToByte);
+
+ /* narrowing towards short */
+ Converter<Short> narrowingToShort = new Converter<Short>()
+ {
+ @Override
+ public Short convert(Object o)
+ {
+ if (o == null) return null;
+ long l = ((Number)o).longValue();
+ if (l < minShort || l > maxShort)
+ {
+ throw new NumberFormatException("value out of range for short type: " + l);
+ }
+ return ((Number) o).shortValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Short.class, Integer.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Long.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Float.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Double.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Number.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Integer.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Long.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Float.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Double.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Integer.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Long.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Float.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Double.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Number.class), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Integer.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Long.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Float.TYPE), narrowingToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Double.TYPE), narrowingToShort);
+
+ /* string to short */
+ Converter<Short> stringToShort = new Converter<Short>()
+ {
+ @Override
+ public Short convert(Object o)
+ {
+ return Short.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Short.class, String.class), stringToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, String.class), stringToShort);
+
+ /* narrowing towards int */
+ Converter<Integer> narrowingToInteger = new Converter<Integer>()
+ {
+ @Override
+ public Integer convert(Object o)
+ {
+ if (o == null) return null;
+ long l = ((Number)o).longValue();
+ if (l < minInt || l > maxInt)
+ {
+ throw new NumberFormatException("value out of range for integer type: " + l);
+ }
+ return ((Number) o).intValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Integer.class, Long.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Float.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Double.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Number.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Long.TYPE), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Float.TYPE), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Double.TYPE), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Long.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Float.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Double.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Number.class), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Long.TYPE), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Float.TYPE), narrowingToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Double.TYPE), narrowingToInteger);
+
+ /* widening towards Integer */
+ Converter<Integer> wideningToInteger = new Converter<Integer>()
+ {
+ @Override
+ public Integer convert(Object o)
+ {
+ if (o == null) return null;
+ return ((Number) o).intValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Integer.class, Short.class), wideningToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Short.TYPE), wideningToInteger);
+
+ /* string to int */
+ Converter<Integer> stringToInteger = new Converter<Integer>()
+ {
+ @Override
+ public Integer convert(Object o)
+ {
+ return Integer.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Integer.class, String.class), stringToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, String.class), stringToInteger);
+
+ /* narrowing towards long */
+ Converter<Long> narrowingToLong = new Converter<Long>()
+ {
+ @Override
+ public Long convert(Object o)
+ {
+ if (o == null) return null;
+ double d = ((Number)o).doubleValue();
+ if (d < minLong || d > maxLong)
+ {
+ throw new NumberFormatException("value out of range for long type: " + d);
+ }
+ return ((Number) o).longValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Long.class, Float.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Double.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Number.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Float.TYPE), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Double.TYPE), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Float.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Double.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Number.class), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Float.TYPE), narrowingToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Double.TYPE), narrowingToLong);
+
+ /* widening towards Long */
+ Converter<Long> wideningToLong = new Converter<Long>()
+ {
+ @Override
+ public Long convert(Object o)
+ {
+ if (o == null) return null;
+ return ((Number) o).longValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Long.class, Short.class), wideningToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Integer.class), wideningToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Short.TYPE), wideningToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Integer.TYPE), wideningToLong);
+
+ /* string to long */
+ Converter<Long> stringToLong = new Converter<Long>()
+ {
+ @Override
+ public Long convert(Object o)
+ {
+ return Long.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Long.class, String.class), stringToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, String.class), stringToLong);
+
+ /* narrowing towards float */
+ Converter<Float> narrowingToFloat = new Converter<Float>()
+ {
+ @Override
+ public Float convert(Object o)
+ {
+ return o == null ? null : ((Number) o).floatValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Float.class, Double.class), narrowingToFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Number.class), narrowingToFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Double.TYPE), narrowingToFloat);
+ standardConverterMap.put(new Pair<>(Float.TYPE, Double.class), narrowingToFloat);
+ standardConverterMap.put(new Pair<>(Float.TYPE, Number.class), narrowingToFloat);
+ standardConverterMap.put(new Pair<>(Float.TYPE, Double.TYPE), narrowingToFloat);
+
+ /* exact towards Float */
+ Converter<Float> toFloat = new Converter<Float>()
+ {
+ @Override
+ public Float convert(Object o)
+ {
+ if (o == null) return null;
+ return ((Number) o).floatValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Float.class, Short.class), toFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Integer.class), toFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Long.class), toFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Short.TYPE), toFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Integer.TYPE), toFloat);
+ standardConverterMap.put(new Pair<>(Float.class, Long.TYPE), toFloat);
+
+ /* string to float */
+ Converter<Float> stringToFloat = new Converter<Float>()
+ {
+ @Override
+ public Float convert(Object o)
+ {
+ return Float.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Float.class, String.class), stringToFloat);
+ standardConverterMap.put(new Pair<>(Float.TYPE, String.class), stringToFloat);
+
+ /* exact or widening towards Double */
+ Converter<Double> toDouble = new Converter<Double>()
+ {
+ @Override
+ public Double convert(Object o)
+ {
+ if (o == null) return null;
+ return ((Number) o).doubleValue();
+ }
+ };
+ standardConverterMap.put(new Pair<>(Double.class, Short.class), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Integer.class), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Long.class), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Float.class), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Number.class), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Short.TYPE), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Integer.TYPE), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Long.TYPE), toDouble);
+ standardConverterMap.put(new Pair<>(Double.class, Float.TYPE), toDouble);
+ standardConverterMap.put(new Pair<>(Double.TYPE, Number.class), toDouble);
+
+ /* string to double */
+ Converter<Double> stringToDouble = new Converter<Double>()
+ {
+ @Override
+ public Double convert(Object o)
+ {
+ return Double.valueOf(String.valueOf(o));
+ }
+ };
+ standardConverterMap.put(new Pair<>(Double.class, String.class), stringToDouble);
+ standardConverterMap.put(new Pair<>(Double.TYPE, String.class), stringToDouble);
+
+ /* boolean to byte */
+ Converter<Byte> booleanToByte = new Converter<Byte>()
+ {
+ @Override
+ public Byte convert(Object o)
+ {
+ return o == null ? null : (Boolean) o ? (byte)1 : (byte)0;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Byte.class, Boolean.class), booleanToByte);
+ standardConverterMap.put(new Pair<>(Byte.class, Boolean.TYPE), booleanToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Boolean.class), booleanToByte);
+ standardConverterMap.put(new Pair<>(Byte.TYPE, Boolean.TYPE), booleanToByte);
+
+ /* boolean to short */
+ Converter<Short> booleanToShort = new Converter<Short>()
+ {
+ @Override
+ public Short convert(Object o)
+ {
+ return o == null ? null : (Boolean) o ? (short)1 : (short)0;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Short.class, Boolean.class), booleanToShort);
+ standardConverterMap.put(new Pair<>(Short.class, Boolean.TYPE), booleanToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Boolean.class), booleanToShort);
+ standardConverterMap.put(new Pair<>(Short.TYPE, Boolean.TYPE), booleanToShort);
+
+ /* boolean to integer */
+ Converter<Integer> booleanToInteger = new Converter<Integer>()
+ {
+ @Override
+ public Integer convert(Object o)
+ {
+ return o == null ? null : (Boolean) o ? (Integer)1 : (Integer)0;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Integer.class, Boolean.class), booleanToInteger);
+ standardConverterMap.put(new Pair<>(Integer.class, Boolean.TYPE), booleanToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Boolean.class), booleanToInteger);
+ standardConverterMap.put(new Pair<>(Integer.TYPE, Boolean.TYPE), booleanToInteger);
+
+ /* boolean to lonf */
+ Converter<Long> booleanToLong = new Converter<Long>()
+ {
+ @Override
+ public Long convert(Object o)
+ {
+ return o == null ? null : (Boolean) o ? 1L : 0L;
+ }
+ };
+ standardConverterMap.put(new Pair<>(Long.class, Boolean.class), booleanToLong);
+ standardConverterMap.put(new Pair<>(Long.class, Boolean.TYPE), booleanToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Boolean.class), booleanToLong);
+ standardConverterMap.put(new Pair<>(Long.TYPE, Boolean.TYPE), booleanToLong);
+
+ /* to string */
+ toString = new Converter<String>()
+ {
+ @Override
+ public String convert(Object o)
+ {
+ return String.valueOf(o);
+ }
+ };
+ }
+
+ /**
+ * Constructor
+ */
+ public TypeConversionHandlerImpl()
+ {
+ converterCacheMap = new ConcurrentHashMap<>();
+ }
+
+ /**
+ * Check to see if the conversion can be done using an explicit conversion
+ * @param actual found argument type
+ * @param formal expected formal type
+ * @return true if actual class can be explicitely converted to expected formal type
+ * @since 2.1
+ */
+ @Override
+ public boolean isExplicitlyConvertible(Type formal, Class actual, boolean possibleVarArg)
+ {
+ /*
+ * for consistency, we also have to check standard implicit convertibility
+ * since it may not have been checked before by the calling code
+ */
+ if ((formal instanceof Class) && (Class)formal == actual ||
+ IntrospectionUtils.isMethodInvocationConvertible(formal, actual, possibleVarArg) ||
+ getNeededConverter(formal, actual) != null)
+ {
+ return true;
+ }
+
+ /* Check var arg */
+ if (possibleVarArg && (formal instanceof Class) && ((Class)formal).isArray())
+ {
+ if (actual.isArray())
+ {
+ actual = actual.getComponentType();
+ }
+ return isExplicitlyConvertible(((Class)formal).getComponentType(), actual, false);
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns the appropriate Converter object needed for an explicit conversion
+ * Returns null if no conversion is needed.
+ *
+ * @param actual found argument type
+ * @param formal expected formal type
+ * @return null if no conversion is needed, or the appropriate Converter object
+ * @since 2.1
+ */
+ @Override
+ public Converter getNeededConverter(Type formal, Class actual)
+ {
+ Pair<Type, Class> key = new Pair<>(formal, actual);
+
+ /* first check for a standard conversion */
+ Converter converter = standardConverterMap.get(key);
+ if (converter == null)
+ {
+ /* then the converters cache map */
+ converter = converterCacheMap.get(key);
+ if (converter == null)
+ {
+ /* check for conversion towards string */
+ if (formal == String.class)
+ {
+ converter = toString;
+ }
+ /* check for String -> Enum constant conversion */
+ else if ((formal instanceof Class) && ((Class)formal).isEnum() && actual == String.class)
+ {
+ final Class<Enum> enumClass = (Class<Enum>)formal;
+ converter = new Converter()
+ {
+ @Override
+ public Object convert(Object o)
+ {
+ return Enum.valueOf(enumClass, (String) o);
+ }
+ };
+ }
+
+ converterCacheMap.put(key, converter == null ? cacheMiss : converter);
+ }
+ }
+ return converter == cacheMiss ? null : converter;
+ }
+
+ /**
+ * Add the given converter to the handler.
+ *
+ * @param formal expected formal type
+ * @param actual provided argument type
+ * @param converter converter
+ * @since 2.1
+ */
+ @Override
+ public void addConverter(Type formal, Class actual, Converter converter)
+ {
+ Pair<Type, Class> key = new Pair<>(formal, actual);
+ converterCacheMap.put(key, converter);
+ if (formal instanceof Class)
+ {
+ Class formalClass = (Class)formal;
+ if (formalClass.isPrimitive())
+ {
+ key = new Pair<>((Type)IntrospectionUtils.getBoxedClass(formalClass), actual);
+ converterCacheMap.put(key, converter);
+ }
+ else
+ {
+ Class unboxedFormal = IntrospectionUtils.getUnboxedClass(formalClass);
+ if (unboxedFormal != formalClass)
+ {
+ key = new Pair<>((Type)unboxedFormal, actual);
+ converterCacheMap.put(key, converter);
+ }
+ }
+ }
+ }
+}
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java Wed Oct 17 11:42:10 2018
@@ -19,6 +19,7 @@ package org.apache.velocity.util.introsp
* under the License.
*/
+import org.apache.commons.lang3.Conversion;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeServices;
@@ -42,6 +43,7 @@ import org.slf4j.Logger;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
@@ -69,7 +71,7 @@ public class UberspectImpl implements Ub
/**
* the conversion handler
*/
- protected ConversionHandler conversionHandler;
+ protected TypeConversionHandler conversionHandler;
/**
* runtime services
@@ -86,7 +88,7 @@ public class UberspectImpl implements Ub
introspector = new Introspector(log, conversionHandler);
}
- public ConversionHandler getConversionHandler()
+ public TypeConversionHandler getConversionHandler()
{
return conversionHandler;
}
@@ -95,6 +97,7 @@ public class UberspectImpl implements Ub
* sets the runtime services
* @param rs runtime services
*/
+ @SuppressWarnings("deprecation")
public void setRuntimeServices(RuntimeServices rs)
{
rsvc = rs;
@@ -129,17 +132,45 @@ public class UberspectImpl implements Ub
throw new VelocityException("Cannot access class '" + conversionHandlerClass + "'", ae);
}
- if (!(o instanceof ConversionHandler))
+ if (o instanceof ConversionHandler)
+ {
+ log.warn("The ConversionHandler interface is deprecated - see the TypeConversionHandler interface");
+ final ConversionHandler ch = (ConversionHandler)o;
+ conversionHandler = new TypeConversionHandler()
+ {
+ @Override
+ public boolean isExplicitlyConvertible(Type formal, Class actual, boolean possibleVarArg)
+ {
+ if (formal instanceof Class) return ch.isExplicitlyConvertible((Class)formal, actual, possibleVarArg);
+ else throw new UnsupportedOperationException("This conversion handler doesn't handle Types which aren't Classes");
+ }
+
+ @Override
+ public Converter getNeededConverter(Type formal, Class actual)
+ {
+ if (formal instanceof Class) return ch.getNeededConverter((Class)formal, actual);
+ else throw new UnsupportedOperationException("This conversion handler doesn't handle Types which aren't Classes");
+ }
+
+ @Override
+ public void addConverter(Type formal, Class actual, Converter converter)
+ {
+ if (formal instanceof Class) ch.addConverter((Class)formal, actual, converter);
+ else throw new UnsupportedOperationException("This conversion handler doesn't handle Types which aren't Classes");
+ }
+ };
+ }
+ else if (!(o instanceof TypeConversionHandler))
{
String err = "The specified class for ResourceManager (" + conversionHandlerClass
- + ") does not implement " + ConversionHandler.class.getName()
+ + ") does not implement " + TypeConversionHandler.class.getName()
+ "; Velocity is not initialized correctly.";
log.error(err);
throw new VelocityException(err);
}
- conversionHandler = (ConversionHandler) o;
+ conversionHandler = (TypeConversionHandler) o;
}
}
@@ -256,7 +287,7 @@ public class UberspectImpl implements Ub
Method m = introspector.getMethod(obj.getClass(), methodName, args);
if (m != null)
{
- return new VelMethodImpl(m, false, getNeededConverters(m.getParameterTypes(), args));
+ return new VelMethodImpl(m, false, getNeededConverters(m.getGenericParameterTypes(), args));
}
Class cls = obj.getClass();
@@ -269,7 +300,7 @@ public class UberspectImpl implements Ub
{
// and create a method that knows to wrap the value
// before invoking the method
- return new VelMethodImpl(m, true, getNeededConverters(m.getParameterTypes(), args));
+ return new VelMethodImpl(m, true, getNeededConverters(m.getGenericParameterTypes(), args));
}
}
// watch for classes, to allow calling their static methods (VELOCITY-102)
@@ -278,7 +309,7 @@ public class UberspectImpl implements Ub
m = introspector.getMethod((Class)obj, methodName, args);
if (m != null)
{
- return new VelMethodImpl(m, false, getNeededConverters(m.getParameterTypes(), args));
+ return new VelMethodImpl(m, false, getNeededConverters(m.getGenericParameterTypes(), args));
}
}
return null;
@@ -288,7 +319,7 @@ public class UberspectImpl implements Ub
* get the list of needed converters to adapt passed argument types to method types
* @return null if not conversion needed, otherwise an array containing needed converters
*/
- private Converter[] getNeededConverters(Class[] expected, Object[] provided)
+ private Converter[] getNeededConverters(Type[] expected, Object[] provided)
{
if (conversionHandler == null) return null;
// var args are not handled here - CB TODO
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties Wed Oct 17 11:42:10 2018
@@ -210,7 +210,7 @@ runtime.introspector.uberspect = org.apa
# Sets the data types Conversion Handler used by the default uberspector
# ----------------------------------------------------------------------------
-runtime.conversion.handler.class = org.apache.velocity.util.introspection.ConversionHandlerImpl
+runtime.conversion.handler.class = org.apache.velocity.util.introspection.TypeConversionHandlerImpl
# ----------------------------------------------------------------------------
Modified: velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java?rev=1844087&r1=1844086&r2=1844087&view=diff
==============================================================================
--- velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java (original)
+++ velocity/engine/branches/VELOCITY-892/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java Wed Oct 17 11:42:10 2018
@@ -28,11 +28,11 @@ import org.apache.velocity.context.Conte
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;
import org.apache.velocity.test.BaseTestCase;
-import org.apache.velocity.util.introspection.ConversionHandler;
-import org.apache.velocity.util.introspection.ConversionHandlerImpl;
+import org.apache.velocity.util.introspection.TypeConversionHandlerImpl;
import org.apache.velocity.util.introspection.Converter;
import org.apache.velocity.util.introspection.Info;
import org.apache.velocity.util.introspection.IntrospectionUtils;
+import org.apache.velocity.util.introspection.TypeConversionHandler;
import org.apache.velocity.util.introspection.Uberspect;
import org.apache.velocity.util.introspection.UberspectImpl;
@@ -113,7 +113,7 @@ public class ConversionHandlerTestCase e
Uberspect uberspect = ve.getUberspect();
assertTrue(uberspect instanceof UberspectImpl);
UberspectImpl ui = (UberspectImpl)uberspect;
- ConversionHandler ch = ui.getConversionHandler();
+ TypeConversionHandler ch = ui.getConversionHandler();
assertTrue(ch != null);
ch.addConverter(Float.class, Obj.class, new Converter<Float>()
{
@@ -295,10 +295,10 @@ public class ConversionHandlerTestCase e
public static class Introspect
{
- private ConversionHandler handler;
+ private TypeConversionHandler handler;
public Introspect()
{
- handler = new ConversionHandlerImpl();
+ handler = new TypeConversionHandlerImpl();
}
public boolean isStrictlyConvertible(Class expected, Class provided)
{