JsonPlugin在分析类结构并序列化时,对于CGLig动态生成的类也是按照一般类来看待的。这就导致了如下的问题:

在一个应用中,某些情况下,一个服务类返回的实体并不是原有实体类的对象,而是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()方法:

 1       private   void  bean(Object object)  throws  JSONException {
 2           this .add( " { " );
 3 
 4          BeanInfo info;
 5 
 6           try  {
 7              Class clazz  =  object.getClass();
 8 
 9              info  =  ((object  ==   this .root)  &&   this .ignoreHierarchy)  ?  Introspector
10                      .getBeanInfo(clazz, clazz.getSuperclass())
11                      : Introspector.getBeanInfo(clazz);
12 
13              PropertyDescriptor[] props  =  info.getPropertyDescriptors();
14 
15               boolean  hasData  =   false ;
16               for  ( int  i  =   0 ; i  <  props.length;  ++ i) {
17                  PropertyDescriptor prop  =  props[i];
18                  String name  =  prop.getName();
19                  Method accessor  =  prop.getReadMethod();
20                  Method baseAccessor  =   null // 这里增加一个临时变量作为真实希望序列化的属性的accessor方法引用
21                   if  (clazz.getName().indexOf( " $$EnhancerByCGLIB$$ " >   - 1 ) {   // 如果是CGLIB动态生成的类
22                       try  {
23                           // 下面的逻辑是根据CGLIB动态生成的类名,得到原本的实体类名
24                           // 例如 EntityClassName$$EnhancerByCGLIB$$ac21e这样
25                           // 的类,将返回的是EntityClassName这个类中的相应方法,若
26                           // 获取不到对应方法,则说明要序列化的属性例如hibernateLazyInitializer之类
27                           // 不在原有实体类中,而是仅存在于CGLib生成的子类中,此时baseAccessor
28                           // 保持为null
29                          baseAccessor  =  Class.forName(
30                                  clazz.getName().substring( 0 ,
31                                          clazz.getName().indexOf( " $$ " )))
32                                  .getDeclaredMethod(accessor.getName(),
33                                          accessor.getParameterTypes());
34                      }  catch  (Exception ex) {
35                          log.debug(ex.getMessage());
36                      }
37                  }
38                   else      // 若不是CGLib生成的类,那么要序列化的属性的accessor方法就是该类中的方法。
39                      baseAccessor  =  accessor;
40 
41                   // 这个判断,根据上面的逻辑,使得仅存在于CGLIB生成子类中的属性跳过JSON序列化
42                   if  (baseAccessor  !=   null ) {    
43                      
44                       // 下面的JSON Annotation的获取也修改为从baseAccessor获取,这样避免了
45                       // 由于CGLIB生成子类而导致某些方法上的JSON Annotation丢失导致处理不该
46                       // 序列化的属性
47                      JSON json  =  baseAccessor.getAnnotation(JSON. class );
48                       if  (json  !=   null ) {
49                           if  ( ! json.serialize())
50                               continue ;
51                           else   if  (json.name().length()  >   0 )
52                              name  =  json.name();
53                      }
54 
55                       // ignore "class" and others
56                       if  ( this .shouldExcludeProperty(clazz, prop)) {
57                           continue ;
58                      }
59                      String expr  =   null ;
60                       if  ( this .buildExpr) {
61                          expr  =   this .expandExpr(name);
62                           if  ( this .shouldExcludeProperty(expr)) {
63                               continue ;
64                          }
65                          expr  =   this .setExprStack(expr);
66                      }
67                       if  (hasData) {
68                           this .add( ' , ' );
69                      }
70                      hasData  =   true ;
71 
72                      Object value  =  accessor.invoke(object,  new  Object[ 0 ]);
73                       this .add(name, value, accessor);
74                       if  ( this .buildExpr) {
75                           this .setExprStack(expr);
76                      }
77                  }
78              }
79          }  catch  (Exception e) {
80               throw   new  JSONException(e);
81          }
82 
83           this .add( " } " );
84      }

这样修改之后,原有类中不能存在的属性将不会被序列化,同时,由于不检查生成的类的方法上的JSON标记,而是检查原有类上的标记,这样避免了由于CGLIB导致的Annotation丢失的问题。

在此依然向诸位询问是否JSONPlugin有处理这样的情况的方法。