Polishing

This commit is contained in:
Juergen Hoeller 2014-01-16 16:54:49 +01:00
parent fd13c994c9
commit 16bf501b30
7 changed files with 463 additions and 520 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,30 +17,32 @@
package org.springframework.expression;
/**
* Instances of a type comparator should be able to compare pairs of objects for equality, the specification of the
* return value is the same as for {@link Comparable}.
* Instances of a type comparator should be able to compare pairs of objects for equality.
* The specification of the return value is the same as for {@link java.lang.Comparable}.
*
* @author Andy Clement
* @since 3.0
* @see java.lang.Comparable
*/
public interface TypeComparator {
/**
* Compare two objects.
* Return {@code true} if the comparator can compare these two objects.
* @param firstObject the first object
* @param secondObject the second object
* @return 0 if they are equal, <0 if the first is smaller than the second, or >0 if the first is larger than the
* second
* @throws EvaluationException if a problem occurs during comparison (or they are not comparable)
*/
int compare(Object firstObject, Object secondObject) throws EvaluationException;
/**
* Return true if the comparator can compare these two objects
* @param firstObject the first object
* @param secondObject the second object
* @return true if the comparator can compare these objects
* @return {@code true} if the comparator can compare these objects
*/
boolean canCompare(Object firstObject, Object secondObject);
/**
* Compare two given objects.
* @param firstObject the first object
* @param secondObject the second object
* @return 0 if they are equal, <0 if the first is smaller than the second,
* or >0 if the first is larger than the second
* @throws EvaluationException if a problem occurs during comparison
* (or if they are not comparable in the first place)
*/
int compare(Object firstObject, Object secondObject) throws EvaluationException;
}

View File

@ -35,22 +35,23 @@ public interface TypeConverter {
* to the desired target type.
* @param sourceType a type descriptor that describes the source type
* @param targetType a type descriptor that describes the requested result type
* @return true if that conversion can be performed
* @return {@code true} if that conversion can be performed
*/
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* Convert (may coerce) a value from one type to another, for example from a boolean
* to a string. The typeDescriptor parameter enables support for typed collections -
* if the caller really wishes they can have a List&lt;Integer&gt; for example, rather
* than simply a List.
* Convert (or coerce) a value from one type to another, for example from a
* {@code boolean} to a {@code String}.
* <p>The {@link TypeDescriptor} parameters enable support for typed collections:
* A caller may prefer a {@code List&lt;Integer&gt;}, for example, rather than
* simply any {@code List}.
* @param value the value to be converted
* @param sourceType a type descriptor that supplies extra information about the
* source object
* @param targetType a type descriptor that supplies extra information about the
* requested result type
* @return the converted value
* @throws EvaluationException if conversion is not possible
* @throws EvaluationException if conversion failed or is not possible to begin with
*/
Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,9 +17,12 @@
package org.springframework.expression;
/**
* Implementors of this interface are expected to be able to locate types. They may use custom classloaders
* or the and deal with common package prefixes (java.lang, etc) however they wish. See
* {@link org.springframework.expression.spel.support.StandardTypeLocator} for an example implementation.
* Implementers of this interface are expected to be able to locate types.
* They may use a custom {@link ClassLoader} and/or deal with common
* package prefixes (e.g. {@code java.lang}) however they wish.
*
* <p>See {@link org.springframework.expression.spel.support.StandardTypeLocator}
* for an example implementation.
*
* @author Andy Clement
* @since 3.0
@ -27,11 +30,12 @@ package org.springframework.expression;
public interface TypeLocator {
/**
* Find a type by name. The name may or may not be fully qualified (eg. String or java.lang.String)
* @param typename the type to be located
* @return the class object representing that type
* @throws EvaluationException if there is a problem finding it
* Find a type by name. The name may or may not be fully qualified
* (e.g. {@code String} or {@code java.lang.String}).
* @param typeName the type to be located
* @return the {@code Class} object representing that type
* @throws EvaluationException if there is a problem finding the type
*/
Class<?> findType(String typename) throws EvaluationException;
Class<?> findType(String typeName) throws EvaluationException;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,7 +21,8 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
/**
* A simple basic TypeComparator implementation. It supports comparison of numbers and types implementing Comparable.
* A simple basic {@link TypeComparator} implementation.
* It supports comparison of Numbers and types implementing Comparable.
*
* @author Andy Clement
* @author Juergen Hoeller
@ -29,49 +30,6 @@ import org.springframework.expression.spel.SpelMessage;
*/
public class StandardTypeComparator implements TypeComparator {
@SuppressWarnings("unchecked")
public int compare(Object left, Object right) throws SpelEvaluationException {
// If one is null, check if the other is
if (left == null) {
return right == null ? 0 : -1;
} else if (right == null) {
return 1; // left cannot be null
}
// Basic number comparisons
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof Double || rightNumber instanceof Double) {
double d1 = leftNumber.doubleValue();
double d2 = rightNumber.doubleValue();
return Double.compare(d1,d2);
} else if (leftNumber instanceof Float || rightNumber instanceof Float) {
float f1 = leftNumber.floatValue();
float f2 = rightNumber.floatValue();
return Float.compare(f1,f2);
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
Long l1 = leftNumber.longValue();
Long l2 = rightNumber.longValue();
return l1.compareTo(l2);
} else {
Integer i1 = leftNumber.intValue();
Integer i2 = rightNumber.intValue();
return i1.compareTo(i2);
}
}
try {
if (left instanceof Comparable) {
return ((Comparable) left).compareTo(right);
}
} catch (ClassCastException cce) {
throw new SpelEvaluationException(cce, SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
}
throw new SpelEvaluationException(SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
}
public boolean canCompare(Object left, Object right) {
if (left == null || right == null) {
return true;
@ -85,4 +43,56 @@ public class StandardTypeComparator implements TypeComparator {
return false;
}
@SuppressWarnings("unchecked")
public int compare(Object left, Object right) throws SpelEvaluationException {
// If one is null, check if the other is
if (left == null) {
return (right == null ? 0 : -1);
}
else if (right == null) {
return 1; // left cannot be null at this point
}
// Basic number comparisons
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof Double || rightNumber instanceof Double) {
return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
}
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
return Float.compare(leftNumber.floatValue(), rightNumber.floatValue());
}
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
// Don't call Long.compare here - only available on JDK 1.7+
return compare(leftNumber.longValue(), rightNumber.longValue());
}
else {
// Don't call Integer.compare here - only available on JDK 1.7+
return compare(leftNumber.intValue(), rightNumber.intValue());
}
}
try {
if (left instanceof Comparable) {
return ((Comparable) left).compareTo(right);
}
}
catch (ClassCastException ex) {
throw new SpelEvaluationException(ex, SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
}
throw new SpelEvaluationException(SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
}
private static int compare(int x, int y) {
return (x < y ? -1 : (x > y ? 1 : 0));
}
private static int compare(long x, long y) {
return (x < y ? -1 : (x > y ? 1 : 0));
}
}

View File

@ -18,7 +18,6 @@ package org.springframework.expression.spel.support;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.TypeConverter;
@ -27,8 +26,8 @@ import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
/**
* Default implementation of the {@link TypeConverter} interface, delegating to a core
* Spring {@link ConversionService}.
* Default implementation of the {@link TypeConverter} interface,
* delegating to a core Spring {@link ConversionService}.
*
* @author Juergen Hoeller
* @author Andy Clement
@ -42,6 +41,9 @@ public class StandardTypeConverter implements TypeConverter {
private final ConversionService conversionService;
/**
* Create a StandardTypeConverter for the default ConversionService.
*/
public StandardTypeConverter() {
synchronized (this) {
if (defaultConversionService == null) {
@ -51,6 +53,10 @@ public class StandardTypeConverter implements TypeConverter {
this.conversionService = defaultConversionService;
}
/**
* Create a StandardTypeConverter for the given ConversionService.
* @param conversionService the ConversionService to delegate to
*/
public StandardTypeConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
@ -65,10 +71,6 @@ public class StandardTypeConverter implements TypeConverter {
try {
return this.conversionService.convert(value, sourceType, targetType);
}
catch (ConverterNotFoundException ex) {
throw new SpelEvaluationException(
ex, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());
}
catch (ConversionException ex) {
throw new SpelEvaluationException(
ex, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +16,8 @@
package org.springframework.expression.spel.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.springframework.expression.EvaluationException;
@ -27,8 +27,9 @@ import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.ClassUtils;
/**
* A default implementation of a TypeLocator that uses the context classloader (or any classloader set upon it). It
* supports 'well known' packages so if a type cannot be found it will try the registered imports to locate it.
* A simple implementation of {@link TypeLocator} that uses the context ClassLoader
* (or any ClassLoader set upon it). It supports 'well-known' packages: So if a
* type cannot be found, it will try the registered imports to locate it.
*
* @author Andy Clement
* @author Juergen Hoeller
@ -36,49 +37,30 @@ import org.springframework.util.ClassUtils;
*/
public class StandardTypeLocator implements TypeLocator {
private ClassLoader loader;
private final ClassLoader classLoader;
private final List<String> knownPackagePrefixes = new ArrayList<String>();
private final List<String> knownPackagePrefixes = new LinkedList<String>();
/**
* Create a StandardTypeLocator for the default ClassLoader
* (typically, the thread context ClassLoader).
*/
public StandardTypeLocator() {
this(ClassUtils.getDefaultClassLoader());
}
public StandardTypeLocator(ClassLoader loader) {
this.loader = loader;
// Similar to when writing Java, it only knows about java.lang by default
/**
* Create a StandardTypeLocator for the given ClassLoader.
* @param classLoader the ClassLoader to delegate to
*/
public StandardTypeLocator(ClassLoader classLoader) {
this.classLoader = classLoader;
// Similar to when writing regular Java code, it only knows about java.lang by default
registerImport("java.lang");
}
/**
* Find a (possibly unqualified) type reference - first using the typename as is, then trying any registered
* prefixes if the typename cannot be found.
* @param typename the type to locate
* @return the class object for the type
* @throws EvaluationException if the type cannot be found
*/
public Class<?> findType(String typename) throws EvaluationException {
String nameToLookup = typename;
try {
return this.loader.loadClass(nameToLookup);
}
catch (ClassNotFoundException ey) {
// try any registered prefixes before giving up
}
for (String prefix : this.knownPackagePrefixes) {
try {
nameToLookup = new StringBuilder().append(prefix).append(".").append(typename).toString();
return this.loader.loadClass(nameToLookup);
}
catch (ClassNotFoundException ex) {
// might be a different prefix
}
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typename);
}
/**
* Register a new import prefix that will be used when searching for unqualified types.
* Expected format is something like "java.lang".
@ -88,16 +70,48 @@ public class StandardTypeLocator implements TypeLocator {
this.knownPackagePrefixes.add(prefix);
}
/**
* Remove that specified prefix from this locator's list of imports.
* @param prefix the prefix to remove
*/
public void removeImport(String prefix) {
this.knownPackagePrefixes.remove(prefix);
}
/**
* Return a list of all the import prefixes registered with this StandardTypeLocator.
* @return list of registered import prefixes
* @return a list of registered import prefixes
*/
public List<String> getImportPrefixes() {
return Collections.unmodifiableList(this.knownPackagePrefixes);
}
public void removeImport(String prefix) {
this.knownPackagePrefixes.remove(prefix);
/**
* Find a (possibly unqualified) type reference - first using the type name as-is,
* then trying any registered prefixes if the type name cannot be found.
* @param typeName the type to locate
* @return the class object for the type
* @throws EvaluationException if the type cannot be found
*/
public Class<?> findType(String typeName) throws EvaluationException {
String nameToLookup = typeName;
try {
return this.classLoader.loadClass(nameToLookup);
}
catch (ClassNotFoundException ey) {
// try any registered prefixes before giving up
}
for (String prefix : this.knownPackagePrefixes) {
try {
nameToLookup = prefix + "." + typeName;
return this.classLoader.loadClass(nameToLookup);
}
catch (ClassNotFoundException ex) {
// might be a different prefix
}
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
}
}