ognl type conversion adaption

This commit is contained in:
Keith Donald
2008-07-05 21:21:33 +00:00
parent 045dc129e8
commit 421316013b
11 changed files with 106 additions and 80 deletions

View File

@@ -26,12 +26,21 @@ package org.springframework.binding.convert;
public interface ConversionService {
/**
* Return the default conversion executor capable of converting source objects of the specified
* <code>sourceClass</code> to instances of the <code>targetClass</code>.
* Execute a conversion of the source to the specified target class.
* @param source the source to convert from (may be null)
* @param targetClass the target class to convert to
* @return the converted object
* @throws ConversionException if an exception occurred during the conversion process
*/
public Object executeConversion(Object source, Class targetClass) throws ConversionException;
/**
* Return the conversion executor capable of converting source objects of the specified <code>sourceClass</code>
* to instances of the <code>targetClass</code>.
* <p>
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
* @param sourceClass the source class to convert from
* @param targetClass the target class to convert to
* @param sourceClass the source class to convert from (required)
* @param targetClass the target class to convert to (required)
* @return the executor that can execute instance type conversion, never null
* @throws ConversionExecutorNotFoundException when no suitable conversion executor could be found
*/

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.binding.convert.ConversionException;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionExecutorNotFoundException;
import org.springframework.binding.convert.ConversionService;
@@ -163,6 +164,15 @@ public class GenericConversionService implements ConversionService {
}
}
public Object executeConversion(Object source, Class targetClass) throws ConversionException {
if (source != null) {
ConversionExecutor conversionExecutor = getConversionExecutor(source.getClass(), targetClass);
return conversionExecutor.execute(source);
} else {
return null;
}
}
public Class getClassForAlias(String name) throws IllegalArgumentException {
Class clazz = (Class) aliasMap.get(name);
if (clazz != null) {

View File

@@ -19,6 +19,7 @@ import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserContext;
import org.springframework.binding.expression.ParserException;
@@ -31,13 +32,13 @@ import org.springframework.binding.expression.support.AbstractExpressionParser;
*/
public class BeanWrapperExpressionParser extends AbstractExpressionParser {
private ConversionService conversionService;
private ConversionService conversionService = new DefaultConversionService();
/**
* The conversion service to use to obtain {@link ConversionExecutor conversion executors} that will be adapted to
* {@link PropertiesEditor property editors} for use during a
* {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call.
* @return the conversion service
* {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call. The default if not specified is an
* instance of {@link DefaultConversionService}.
*/
public ConversionService getConversionService() {
return conversionService;

View File

@@ -44,15 +44,12 @@ import org.springframework.util.Assert;
*/
public class ELExpressionParser implements ExpressionParser {
/**
* The ExpressionFactory for constructing EL expressions
*/
private ExpressionFactory expressionFactory;
private ConversionService conversionService = new DefaultConversionService();
private Map contextFactories = new HashMap();
private ConversionService conversionService = new DefaultConversionService();
/**
* Creates a new EL expression parser for standalone usage.
*/
@@ -60,6 +57,22 @@ public class ELExpressionParser implements ExpressionParser {
init(expressionFactory);
}
/**
* The conversion service to use to perform type conversions as needed by the Unified EL system. If not specified,
* the default is an instance of {@link DefaultConversionService}.
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Sets the conversion service to use to perform type conversions as needed by the Unified EL system.
* @param conversionService the conversion service to use
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Register the ELContextFactory for expressions that evaluate the given class of context object.
* @param contextType the expression context class

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.binding.expression.ognl;
import java.lang.reflect.Member;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -23,10 +24,12 @@ import java.util.Map;
import ognl.NoSuchPropertyException;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.TypeConverter;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.PropertyNotFoundException;
@@ -46,14 +49,18 @@ class OgnlExpression implements Expression {
private String expressionString;
private ConversionService conversionService;
/**
* Creates a new OGNL expression.
*/
public OgnlExpression(Object expression, Map variableExpressions, Class expectedResultType, String expressionString) {
public OgnlExpression(Object expression, Map variableExpressions, Class expectedResultType,
String expressionString, ConversionService conversionService) {
this.expression = expression;
this.variableExpressions = variableExpressions;
this.expectedResultType = expectedResultType;
this.expressionString = expressionString;
this.conversionService = conversionService;
}
public boolean equals(Object o) {
@@ -84,7 +91,7 @@ class OgnlExpression implements Expression {
public void setValue(Object context, Object value) {
try {
Map evaluationContext = Ognl.addDefaultContext(context, getVariables(context));
// TODO set TypeConverter here to invoke our ConversionService
Ognl.setTypeConverter(evaluationContext, createTypeConverter());
Ognl.setValue(expression, evaluationContext, context, value);
} catch (NoSuchPropertyException e) {
throw new PropertyNotFoundException(context.getClass(), getExpressionString(), e);
@@ -95,6 +102,15 @@ class OgnlExpression implements Expression {
}
}
private TypeConverter createTypeConverter() {
return new TypeConverter() {
public Object convertValue(Map context, Object target, Member member, String propertyName, Object value,
Class toType) {
return conversionService.executeConversion(value, toType);
}
};
}
public Class getValueType(Object context) {
try {
// OGNL has no native way to get this information

View File

@@ -20,6 +20,8 @@ import ognl.OgnlException;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserContext;
import org.springframework.binding.expression.ParserException;
@@ -32,6 +34,24 @@ import org.springframework.binding.expression.support.AbstractExpressionParser;
*/
public class OgnlExpressionParser extends AbstractExpressionParser {
private ConversionService conversionService = new DefaultConversionService();
/**
* The conversion service to use to perform type conversions as needed by the OGNL system. If not specified, the
* default is an instance of {@link DefaultConversionService}.
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Sets the conversion service to use to perform type conversions as needed by the OGNL system.
* @param conversionService the conversion service to use
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Add a property access strategy for the given class.
* @param clazz the class that contains properties needing access
@@ -44,7 +64,8 @@ public class OgnlExpressionParser extends AbstractExpressionParser {
protected Expression doParseExpression(String expressionString, ParserContext context) throws ParserException {
try {
return new OgnlExpression(Ognl.parseExpression(expressionString), parseVariableExpressions(context
.getExpressionVariables()), context.getExpectedEvaluationResultType(), expressionString);
.getExpressionVariables()), context.getExpectedEvaluationResultType(), expressionString,
conversionService);
} catch (OgnlException e) {
throw new ParserException(expressionString, e);
}

View File

@@ -40,23 +40,6 @@ public class DefaultMapper implements Mapper {
private List mappings = new ArrayList();
private ConversionService conversionService;
/**
* Returns the conversion service to use to perform type conversions as needed by mapping operations. May be null.
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Sets the conversion service to use to perform type conversions as needed by mapping operations. Optional.
* @param conversionService the conversion service;
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Add a mapping to this mapper.
* @param mapping the mapping to add (required)
@@ -80,7 +63,7 @@ public class DefaultMapper implements Mapper {
logger.debug("Beginning mapping between source [" + source.getClass().getName() + "] and target ["
+ target.getClass().getName() + "]");
}
DefaultMappingContext context = new DefaultMappingContext(source, target, conversionService);
DefaultMappingContext context = new DefaultMappingContext(source, target);
Iterator it = mappings.iterator();
while (it.hasNext()) {
DefaultMapping mapping = (DefaultMapping) it.next();

View File

@@ -21,7 +21,6 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.convert.ConversionExecutionException;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.mapping.Mapping;
import org.springframework.binding.mapping.MappingResult;
@@ -48,12 +47,9 @@ public class DefaultMappingContext {
private List mappingResults;
private ConversionService conversionService;
public DefaultMappingContext(Object source, Object target, ConversionService conversionService) {
public DefaultMappingContext(Object source, Object target) {
this.source = source;
this.target = target;
this.conversionService = conversionService;
this.mappingResults = new ArrayList();
}
@@ -71,14 +67,6 @@ public class DefaultMappingContext {
return target;
}
/**
* Returns the conversion service that can be used to perform type conversions during the mapping process. May be
* null if no externally managed conversion service is provided.
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Returns the current mapping.
* @return the current mapping