读书人

由一个bug瞧Struts2的类型转换器

发布时间: 2012-09-21 15:47:26 作者: rapoo

由一个bug观Struts2的类型转换器

?

Bug.:

?

?/-- Encapsulated exception ------------\

java.lang.NoSuchMethodException:setYycbSq([Ljava.lang.String;)

???? atognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:810)

???? atognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)

???? at ognl.ObjectPropertyAccessor.setPossibleProperty

(ObjectPropertyAccessor.java:75)

???? atognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:

131)

???? atcom.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty

(ObjectAccessor.java:28)

???? atognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)

???? atognl.ASTProperty.setValueBody(ASTProperty.java:101)

???? atognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)

?

在使用Struts2框架开发时,有时会遇到上面的异常,Action类里定义的实体类对象的属性或者直接在action中定义的属性变量中如有Double类型或Float类型时,当页面传值为 0 ,0.0 ,0.00 等为0 的值时,有时很可能报上面的异常,原因是用户请求后进入到相应的Action中,首先执行的是封装页面获取的属性值,即调用属性的get(),set()方法,此时由于struts2核心包的版本低或者jar包冲突覆盖部分功能等问题,不能处理将从页面获取的“0”或“0.0”,“0.00” 转换成Double类型或Float类型(但可以转换成Integer类型),故在通过调用set()方法封装页面属性值时就会报类型转换的异常。

?

?使用Struts2框架,在页面传 0,或 0.0 时,这个异常也不是一定会出现的,有时OGNL也可以帮你正常转换成功,但如果因为jar包或其他问题而出现时这样的bug时,你可以考虑去下载最新版本的jar包;或者在页面传值时加以限定,比如为Double值时要求所传值大于0等;也可以在action里定义变量时尽量用String类型代替Double和Float类型(这样就没利用Struts2类型自动转换这个优点了)。

注意,对于数组的类型转换将按造数组元素的类型来单独转换每一个元素。而在其他类型转换中,如果转换无法实现, 将使用标准的类型转换错误报告。


注意:在Struts2压缩包是没有ognl的源代码的,需要读者自己再到ognl官网去下一个源代码的压缩包,随便选择一版本下载,这一部分代码实现都大同小异,当然最好使用版本相符的版本。


package ognl;/*省略导入的包*/public abstract class OgnlOps implements NumericTypes{ /*省略其他的方法函数*/ public static Object convertValue( Object value, Class toType){ Object result = null; if (value != null) { //不同类型的具体转换 if ( value.getClass().isArray() && toType.isArray() ) { Class componentType = toType.getComponentType(); result = Array.newInstance(componentType, Array.getLength(value)); for (int i = 0, icount = Array.getLength(value); i < icount; i++) { Array.set(result, i, convertValue(Array.get(value, i), componentType)); } } else { if ( ( toType == Integer.class ) || ( toType == Integer.TYPE ) ) result = new Integer((int)longValue(value)); if ( ( toType == Double.class ) || ( toType == Double.TYPE ) ) result = new Double(doubleValue(value)); if ( ( toType == Boolean.class ) || ( toType == Boolean.TYPE ) ) result = booleanValue(value) ? Boolean.TRUE : Boolean.FALSE; if ( ( toType == Byte.class ) || ( toType == Byte.TYPE ) ) result = new Byte((byte)longValue(value)); if ( ( toType == Character.class ) || ( toType == Character.TYPE ) ) result = new Character((char)longValue(value)); if ( ( toType == Short.class ) || ( toType == Short.TYPE ) ) result = new Short((short)longValue(value)); if ( ( toType == Long.class ) || ( toType == Long.TYPE ) ) result = new Long(longValue(value)); if ( ( toType == Float.class ) || ( toType == Float.TYPE ) ) result = new Float(doubleValue(value)); if ( toType == BigInteger.class ) result = bigIntValue(value); if ( toType == BigDecimal.class ) result = bigDecValue(value); if ( toType == String.class ) result = stringValue(value); } } else { if (toType.isPrimitive()) { result = OgnlRuntime.getPrimitiveDefaultValue(toType); } } return result; }}

??????

?????? 看到这个类的源代码,我们只对convertValue( Object value, Class toType)函数感兴趣,可以看到它是一个静态方法,正是这个函数完成许多基本的类型转换。从上面代码中应该很清楚Struts2默认的类型转换是怎么实现的了。代码中粗体的部分就是对应的可以被转化的类型,用了多个if/else语句,完成了常用类型的转换。每种类型的转换方法都不一样,具体转换代码如源代码所示。这个类当中还有许多其他函数,在此省略了。

通过查找和分析我们发现,这个类型转换的操作早就在ognl中实现,Struts2只是引用了这个包中的函数,然后在自己的源码中进行了一些封装,以便使用的时候可以方便的访问到,不用再去访问ognl中的函数。当然Struts2早就把ognl包作为必须装载的jar包之一。

?

??


By the way,供大家交流Pentaho的圈子,里面可以共享有关pentahoBI平台学习的资料,期待您的加入! http://pentahofrends.group.iteye.com/group/share

?

?

1 楼 kimmking 2010-11-07 /-- Encapsulated exception ------------\

java.lang.NoSuchMethodException: setYycbSq


看起来不是转换问题,而是有地方写错了吧。 2 楼 ruinxdgzy 2010-11-07 回复1楼:
测试过了,只要是大于0的double类型数值都不报错,唯独输入0或 0.0就报错,后来没办法换了最新版本的jar包才解决。而在另一个项目中jar包版本虽低但却不报错。很是郁闷呢。