Author: tschneider Date: Tue Nov 6 20:00:20 2007 New Revision: 592605 URL: http://svn.apache.org/viewvc?rev=592605&view=rev Log: added type conversion
Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/CompoundRootELContext.java struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelReflectionProvider.java struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStack.java struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStackFactory.java struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/PropertyValueExpression.java struts/sandbox/trunk/struts2-juel-plugin/src/test/java/com/googlecode/struts2juel/JuelTest.java Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/CompoundRootELContext.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/CompoundRootELContext.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/CompoundRootELContext.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/CompoundRootELContext.java Tue Nov 6 20:00:20 2007 @@ -1,7 +1,6 @@ package com.googlecode.struts2juel; import javax.el.ArrayELResolver; -import javax.el.BeanELResolver; import javax.el.CompositeELResolver; import javax.el.ELContext; import javax.el.ELResolver; @@ -11,33 +10,39 @@ import javax.el.ResourceBundleELResolver; import javax.el.VariableMapper; +import com.googlecode.struts2juel.elresolvers.XWorkBeanELResolver; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.util.CompoundRoot; /** - * An implementation of SimpleContext that knows about the ValueStack's CompoundRoot. + * An implementation of SimpleContext that knows about the ValueStack's + * CompoundRoot. */ public class CompoundRootELContext extends ELContext { - private VariableMapper variableMapper; - private FunctionMapper functionMapper = new NullFunctionMapper(); + private VariableMapper variableMapper; + private FunctionMapper functionMapper = new NullFunctionMapper(); + private XWorkConverter xworkConverter; - private static final ELResolver DEFAULT_RESOLVER_READ_WRITE = new CompositeELResolver() { + private static final ELResolver DEFAULT_RESOLVER_READ_WRITE = new CompositeELResolver() { { add(new ArrayELResolver(false)); add(new ListELResolver(false)); add(new MapELResolver(false)); add(new ResourceBundleELResolver()); - add(new BeanELResolver(false)); + add(new XWorkBeanELResolver(false)); } }; - - public CompoundRootELContext(CompoundRoot root) { - variableMapper = new CompoundRootVariableMapper(root); - } - - @Override - public VariableMapper getVariableMapper() { - return variableMapper; - } + + public CompoundRootELContext(XWorkConverter xworkConverter, + CompoundRoot root) { + this.xworkConverter = xworkConverter; + variableMapper = new CompoundRootVariableMapper(root); + } + + @Override + public VariableMapper getVariableMapper() { + return variableMapper; + } @Override public ELResolver getELResolver() { @@ -47,5 +52,16 @@ @Override public FunctionMapper getFunctionMapper() { return functionMapper; + } + + public XWorkConverter getXworkConverter() { + return xworkConverter; + } + + public Object convertType(Object value, Class toType) { + if (toType == null) { + return value; + } + return xworkConverter.convertValue(null, value, toType); } } Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelReflectionProvider.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelReflectionProvider.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelReflectionProvider.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelReflectionProvider.java Tue Nov 6 20:00:20 2007 @@ -6,6 +6,8 @@ import javax.el.ExpressionFactory; import javax.el.ValueExpression; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.ognl.OgnlReflectionProvider; import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.reflection.ReflectionException; @@ -15,6 +17,12 @@ */ public class JuelReflectionProvider extends OgnlReflectionProvider { private ExpressionFactory factory; + private XWorkConverter xworkConverter; + + @Inject + public void setXWorkConverter(XWorkConverter conv) { + this.xworkConverter = conv; + } public void initExpressionFactory() { if (factory == null) { @@ -27,7 +35,7 @@ initExpressionFactory(); CompoundRoot compoundRoot = new CompoundRoot(); compoundRoot.add(root); - ELContext elContext = new CompoundRootELContext(compoundRoot); + ELContext elContext = new CompoundRootELContext(xworkConverter, compoundRoot); // parse our expression ValueExpression valueExpr = factory.createValueExpression(elContext, expr, String.class); @@ -39,7 +47,7 @@ initExpressionFactory(); CompoundRoot compoundRoot = new CompoundRoot(); compoundRoot.add(root); - ELContext elContext = new CompoundRootELContext(compoundRoot); + ELContext elContext = new CompoundRootELContext(xworkConverter, compoundRoot); // parse our expression ValueExpression valueExpr = factory.createValueExpression(elContext, expr, String.class); Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStack.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStack.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStack.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStack.java Tue Nov 6 20:00:20 2007 @@ -9,6 +9,7 @@ import javax.el.PropertyNotFoundException; import javax.el.ValueExpression; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.ValueStack; @@ -20,19 +21,27 @@ private transient Map context; private Class defaultType; private Map overrides; + private XWorkConverter xworkConverter; private ExpressionFactory factory; private ELContext elContext; - public JuelValueStack(ExpressionFactory factory) { - this.factory = factory; - setRoot(new CompoundRoot()); + public JuelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter) { + this(factory, xworkConverter, new CompoundRoot()); + } + + public JuelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter, ValueStack vs) { + this(factory, xworkConverter, new CompoundRoot(vs.getRoot())); } - public JuelValueStack(ExpressionFactory factory, ValueStack vs) { + public JuelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter, CompoundRoot root) { + this.xworkConverter = xworkConverter; this.factory = factory; - setRoot(new CompoundRoot(vs.getRoot())); + setRoot(new CompoundRoot()); } public String findString(String expr) { @@ -64,8 +73,11 @@ } // parse our expression ValueExpression valueExpr = factory.createValueExpression( - elContext, expr, asType); + elContext, expr, Object.class); Object retVal = valueExpr.getValue(elContext); + if (!Object.class.equals(asType)) { + retVal = xworkConverter.convertValue(null, retVal, asType); + } return retVal; } catch (PropertyNotFoundException e) { // property not found @@ -127,7 +139,7 @@ expr = "${" + expr + "}"; } // hack to allow parameters to be set back - // juel doesn't support setting String[] values on String properties + // uel doesn't support setting String[] values on String properties if (value != null && value instanceof String[] && ((String[]) value).length == 1) { value = ((String[]) value)[0]; @@ -151,6 +163,6 @@ this.context = new TreeMap(); context.put(VALUE_STACK, this); this.root = root; - this.elContext = new CompoundRootELContext(root); + this.elContext = new CompoundRootELContext(xworkConverter, root); } } Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStackFactory.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStackFactory.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStackFactory.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/JuelValueStackFactory.java Tue Nov 6 20:00:20 2007 @@ -2,6 +2,8 @@ import javax.el.ExpressionFactory; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.ValueStackFactory; @@ -11,19 +13,26 @@ public class JuelValueStackFactory implements ValueStackFactory { private ExpressionFactory factory; + private XWorkConverter xworkConverter; + + @Inject + public void setXWorkConverter(XWorkConverter conv) { + this.xworkConverter = conv; + } + public void initExpressionFactory() { if (factory == null) { factory = ExpressionFactoryLocator.locateExpressFactory(); } } - - public ValueStack createValueStack() { - initExpressionFactory(); - return new JuelValueStack(factory); - } - - public ValueStack createValueStack(ValueStack stack) { - initExpressionFactory(); - return new JuelValueStack(factory, stack); - } + + public ValueStack createValueStack() { + initExpressionFactory(); + return new JuelValueStack(factory, xworkConverter); + } + + public ValueStack createValueStack(ValueStack stack) { + initExpressionFactory(); + return new JuelValueStack(factory, xworkConverter, stack); + } } Modified: struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/PropertyValueExpression.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/PropertyValueExpression.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/PropertyValueExpression.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/main/java/com/googlecode/struts2juel/PropertyValueExpression.java Tue Nov 6 20:00:20 2007 @@ -7,14 +7,18 @@ import org.apache.commons.beanutils.PropertyUtils; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; + /** * A value expression that uses a javabean as the root of the value expression. */ public class PropertyValueExpression extends ValueExpression { private Object object; private String property; + private XWorkConverter xworkConverter; public PropertyValueExpression(Object object, String property) { + this.xworkConverter = xworkConverter; this.object = object; this.property = property; } @@ -33,7 +37,7 @@ } @Override - public Class<?> getType(ELContext arg0) { + public Class<?> getType(ELContext context) { try { return PropertyUtils.getPropertyType(object, property); } catch (IllegalAccessException e) { @@ -46,7 +50,7 @@ } @Override - public Object getValue(ELContext arg0) { + public Object getValue(ELContext context) { try { return PropertyUtils.getSimpleProperty(object, property); } catch (IllegalAccessException e) { @@ -59,14 +63,17 @@ } @Override - public boolean isReadOnly(ELContext arg0) { + public boolean isReadOnly(ELContext context) { return !PropertyUtils.isWriteable(object, property); } @Override - public void setValue(ELContext arg0, Object obj) { + public void setValue(ELContext context, Object value) { try { - PropertyUtils.setSimpleProperty(object, property, obj); + Class propType = PropertyUtils.getPropertyType(object, property); + XWorkConverter xworkConverter = ((CompoundRootELContext) context).getXworkConverter(); + Object convertedValue = xworkConverter.convertValue(value, propType); + PropertyUtils.setSimpleProperty(object, property, convertedValue); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { Modified: struts/sandbox/trunk/struts2-juel-plugin/src/test/java/com/googlecode/struts2juel/JuelTest.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-juel-plugin/src/test/java/com/googlecode/struts2juel/JuelTest.java?rev=592605&r1=592604&r2=592605&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-juel-plugin/src/test/java/com/googlecode/struts2juel/JuelTest.java (original) +++ struts/sandbox/trunk/struts2-juel-plugin/src/test/java/com/googlecode/struts2juel/JuelTest.java Tue Nov 6 20:00:20 2007 @@ -1,55 +1,155 @@ package com.googlecode.struts2juel; import java.lang.reflect.InvocationTargetException; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.Map; import javax.el.ExpressionFactory; -import junit.framework.TestCase; +import org.apache.struts2.util.StrutsTypeConverter; +import com.opensymphony.xwork2.XWorkTestCase; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.util.CompoundRoot; -public class JuelTest extends TestCase { +public class JuelTest extends XWorkTestCase { + private ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); + private XWorkConverter converter; + + private class DateConverter extends StrutsTypeConverter { + private DateFormat format = DateFormat.getDateInstance(); + @Override + public Object convertFromString(Map context, String[] values, + Class toClass) { + try { + return format.parseObject(values[0]); + } catch (ParseException e) { + return null; + } + } + + @Override + public String convertToString(Map context, Object o) { + return format.format(o); + } + + } - public void testBasicFind() throws IllegalAccessException, - InvocationTargetException, NoSuchMethodException { - ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); - - CompoundRoot root = new CompoundRoot(); - TestObject obj = new TestObject(); - root.add(obj); - JuelValueStack stack = new JuelValueStack(factory); - stack.setRoot(root); - stack.setValue("${value}", "Hello World"); - String value = stack.findString("${value}"); - assertEquals("Hello World", value); - } - - public void testNotFound() throws IllegalAccessException, - InvocationTargetException, NoSuchMethodException { - ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); - - CompoundRoot root = new CompoundRoot(); - TestObject obj = new TestObject(); - root.add(obj); - JuelValueStack stack = new JuelValueStack(factory); - stack.setRoot(root); - stack.setValue("${value}", "Hello World"); - String value = stack.findString("${VALUENOTHERE}"); - assertNull(value); - - value = stack.findString("VALUENOTHERE"); - assertNull(value); - } - - public class TestObject { - private String value; - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - } + protected void setUp() throws Exception { + super.setUp(); + + converter = container.getInstance(XWorkConverter.class); + converter.registerConverter("java.util.Date", new DateConverter()); + } + + public void testBasicFind() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + JuelValueStack stack = new JuelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${value}", "Hello World"); + String value = stack.findString("${value}"); + assertEquals("Hello World", value); + + stack.setValue("${age}", "56"); + String age = stack.findString("${age}"); + assertEquals("56", age); + } + + public void test2LevelSet() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + TestObject nestedObj = new TestObject(); + obj.setInner(nestedObj); + root.add(obj); + JuelValueStack stack = new JuelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${inner.age}", "66"); + assertEquals(66, obj.getInner().getAge()); + } + + public void testTypeConversion() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + TestObject inner = new TestObject(); + obj.setInner(inner); + root.add(obj); + JuelValueStack stack = new JuelValueStack(factory, converter); + stack.setRoot(root); + + stack.setValue("${age}", "22"); + assertEquals(stack.findValue("${age}"), obj.getAge()); + + stack.setValue("${inner.value}", "George"); + assertEquals(stack.findValue("${inner.value}"), obj.getInner() + .getValue()); + + stack.setValue("${inner.age}", "44"); + assertEquals(stack.findValue("${inner.age}"), obj.getInner().getAge()); + + stack.setValue("${date}", new Date()); + assertEquals(stack.findString("${date}"), obj.getDate()); + } + + public void testNotFound() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + JuelValueStack stack = new JuelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${value}", "Hello World"); + String value = stack.findString("${VALUENOTHERE}"); + assertNull(value); + + value = stack.findString("VALUENOTHERE"); + assertNull(value); + } + + public class TestObject { + private String value; + private int age; + private Date date; + private TestObject inner; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public TestObject getInner() { + return inner; + } + + public void setInner(TestObject inner) { + this.inner = inner; + } + + } }