锁定老帖子 主题:当Jsonplugin遇到CGLIB
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-09-03
在一个应用中,某些情况下,一个服务类返回的实体并不是原有实体类的对象,而是CGLib动态生成的子类。例如使用Hibernate的时候,某些情况下DAO返回的是EntityClassName$$EnhancerByCGLIB$$ac21e这样的类的对象。Hibernate在这个子类中添加了hibernateLazyInitializer等等的附加属性。由于jsonplugin并不区分类和动态生成的类,所以也会试图序列化hibernateLazyInitializer属性,从而导致出现如下的异常: java.sql.SQLException: Positioned Update not supported. at com.mysql.jdbc.ResultSet.getCursorName(ResultSet.java:1800) 另外,CGLIB生成的类,某些方法上的@JSON标记奇怪的丢失了。导致标记了@JSON(serialize=false)的属性也被序列化。 在网上查了很久没有发现相关的文章,所以无奈就自己动手修改jsonplugin的代码了。 类:com.googlecode.jsonplugin.JSONWriter,修改bean()方法: private void bean(Object object) throws JSONException { this.add("{"); BeanInfo info; try { Class clazz = object.getClass(); info = ((object == this.root) && this.ignoreHierarchy) ? Introspector .getBeanInfo(clazz, clazz.getSuperclass()) : Introspector.getBeanInfo(clazz); PropertyDescriptor[] props = info.getPropertyDescriptors(); boolean hasData = false; for (int i = 0; i < props.length; ++i) { PropertyDescriptor prop = props[i]; String name = prop.getName(); Method accessor = prop.getReadMethod(); Method baseAccessor = null; //这里增加一个临时变量作为真实希望序列化的属性的accessor方法引用 if (clazz.getName().indexOf("$$EnhancerByCGLIB$$") > -1) { //如果是CGLIB动态生成的类 try { //下面的逻辑是根据CGLIB动态生成的类名,得到原本的实体类名 //例如 EntityClassName$$EnhancerByCGLIB$$ac21e这样 //的类,将返回的是EntityClassName这个类中的相应方法,若 //获取不到对应方法,则说明要序列化的属性例如hibernateLazyInitializer之类 //不在原有实体类中,而是仅存在于CGLib生成的子类中,此时baseAccessor //保持为null baseAccessor = Class.forName( clazz.getName().substring(0, clazz.getName().indexOf("$$"))) .getDeclaredMethod(accessor.getName(), accessor.getParameterTypes()); } catch (Exception ex) { log.debug(ex.getMessage()); } } else //若不是CGLib生成的类,那么要序列化的属性的accessor方法就是该类中的方法。 baseAccessor = accessor; //这个判断,根据上面的逻辑,使得仅存在于CGLIB生成子类中的属性跳过JSON序列化 if (baseAccessor != null) { //下面的JSON Annotation的获取也修改为从baseAccessor获取,这样避免了 //由于CGLIB生成子类而导致某些方法上的JSON Annotation丢失导致处理不该 //序列化的属性 JSON json = baseAccessor.getAnnotation(JSON.class); if (json != null) { if (!json.serialize()) continue; else if (json.name().length() > 0) name = json.name(); } //ignore "class" and others if (this.shouldExcludeProperty(clazz, prop)) { continue; } String expr = null; if (this.buildExpr) { expr = this.expandExpr(name); if (this.shouldExcludeProperty(expr)) { continue; } expr = this.setExprStack(expr); } if (hasData) { this.add(','); } hasData = true; Object value = accessor.invoke(object, new Object[0]); this.add(name, value, accessor); if (this.buildExpr) { this.setExprStack(expr); } } } } catch (Exception e) { throw new JSONException(e); } this.add("}"); } 这样修改之后,原有类中不能存在的属性将不会被序列化,同时,由于不检查生成的类的方法上的JSON标记,而是检查原有类上的标记,这样避免了由于CGLIB导致的Annotation丢失的问题。 在此依然向诸位询问是否JSONPlugin有处理这样的情况的方法。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-09-09
hibernate的话set default-lazy=false也可以避免cglib.
我也遇到过你这个问题,你这种解决办法很好 |
|
返回顶楼 | |
发表时间:2007-10-16
似乎去掉不想序列化属性的get方法也能解决这个问题,当然前提是这个get方法没有用!!
|
|
返回顶楼 | |
发表时间:2007-10-24
1.对服务增加java关键字transient,避免服务类被序列化
2.仍然还是需要修改JSONWriter 0.18已经放出来了,好像这个问题还是没有解决 参见http://code.google.com/p/jsonplugin/issues/detail?id=18&can=1&q=JSONException问题报告 当前的代码 http://www.google.com/codesearch?hl=en&q=show:2yr3KDMGcT8:ivhek6ZCpWc:2UkBsRKRjXY&sa=N&ct=rd&cs_p=http://jsonplugin.googlecode.com/svn&cs_f=trunk/src/main/java/com/googlecode/jsonplugin/JSONWriter.java&start=1 |
|
返回顶楼 | |
发表时间:2007-10-29
也遇到这样的问题,
hibernate的lazy机制,也被jsonplugin序列化 导致lazy失效, 类的序列化被一层层地序列化下去,以致于类的关系出形N多的查询 |
|
返回顶楼 | |
发表时间:2007-10-29
realghost819 写道 hibernate的话set default-lazy=false也可以避免cglib.
我也遇到过你这个问题,你这种解决办法很好 期待你更详细的说明 |
|
返回顶楼 | |
发表时间:2008-05-28
loveyeah 写道 也遇到这样的问题,
hibernate的lazy机制,也被jsonplugin序列化 导致lazy失效, 类的序列化被一层层地序列化下去,以致于类的关系出形N多的查询 有什么好的解决方法?? 我也遇到这样的问题!! |
|
返回顶楼 | |
发表时间:2008-05-28
<param name="excludeProperties"> 你不要的属性 </param>
这样应该可以了吧 |
|
返回顶楼 | |
发表时间:2008-05-28
用反射 如果mothed的返回类型是set那就不加载
|
|
返回顶楼 | |
发表时间:2008-05-29
xmvigour 写道 <param name="excludeProperties"> 你不要的属性 </param>
这样应该可以了吧 这个能过滤Action里面的一个List里面的POJO的某个属性吗?如果能应该咋写啊?谢谢啊 |
|
返回顶楼 | |