package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.el.ValueExpression;
import org.springframework.binding.convert.ConversionException;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.ValueCoercionException;
import org.springframework.util.Assert;
/**
* A ValueExpression decorator that decorates a target ValueExpression returned by a EL Implementation's
* {@link ExpressionFactory} to allow use of Spring's type conversion system for coersing expression values.
*
* The Unified EL specification currently provides no standard way of plugging in custom type converters. This decorator
* allows Spring type converters to be utilized with any EL implementation.
*
* @author Keith Donald
*/
class BindingValueExpression extends ValueExpression {
private ValueExpression targetExpression;
private Class<?> expectedType;
private ConversionService conversionService;
private boolean template;
public BindingValueExpression(ValueExpression targetExpression, Class<?> expectedType,
ConversionService conversionService, boolean template) {
Assert.notNull(expectedType, "The expectedType Class is required");
Assert.notNull(conversionService, "The ConversionService to perform type coersions is required");
this.targetExpression = targetExpression;
this.expectedType = expectedType;
this.conversionService = conversionService;
this.template = template;
}
public Class<?> getExpectedType() {
return targetExpression.getExpectedType();
}
public Class<?> getType(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException {
return targetExpression.getType(context);
}
public Object getValue(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException,
ValueCoercionException {
Object value = targetExpression.getValue(context);
return convertValueIfNecessary(value, expectedType, context);
}
public boolean isReadOnly(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException {
return targetExpression.isReadOnly(context);
}
public void setValue(ELContext context, Object value) throws NullPointerException, PropertyNotFoundException,
PropertyNotWritableException, ELException, ValueCoercionException {
value = convertValueIfNecessary(value, targetExpression.getType(context), context);
targetExpression.setValue(context, value);
}
public String getExpressionString() {
if (template) {
return targetExpression.getExpressionString();
} else {
String rawExpressionString = targetExpression.getExpressionString();
return rawExpressionString.substring("#{".length(), rawExpressionString.length() - 1);
}
}
public boolean isLiteralText() {
return targetExpression.isLiteralText();
}
public boolean equals(Object obj) {
if (!(obj instanceof BindingValueExpression)) {
return false;
}
BindingValueExpression exp = (BindingValueExpression) obj;
return targetExpression.equals(exp.targetExpression);
}
public int hashCode() {
return targetExpression.hashCode();
}
private Object convertValueIfNecessary(Object value, Class<?> expectedType, Object context)
throws ValueCoercionException {
if (expectedType == null) {
return value;
} else {
try {
return conversionService.executeConversion(value, expectedType);
} catch (ConversionException e) {
throw new ValueCoercionException(context.getClass(), getExpressionString(), value, expectedType, e);
}
}
}
}