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); } } } }