彻底解决SSH架构中的Hibernate懒加载问题

来源:互联网 发布:mysql 网易镜像 编辑:程序博客网 时间:2024/05/07 15:34

 在客户端使用AJAX框架,服务端采用Struts2+Spring+Hibernate的架构中,经常会遇到Hibernate懒加载的问题 ,异常为:

 

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role  


      相信大家经常可以在网上看到相关的技术文章,大致是在web.xml中加上openSessionFilter,代码如下:

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <filter>  
  2.   <filter-name>hibernateFilter</filter-name>  
  3.   <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>  
  4. </filter>  


 

        如果你真的亲自去写代码了,你会发现这个方法根本不管用,原因在于Struts2的JSON插件使用反射技术,会调用关联对象的get方法获取对象的实例,从而触发Hibernate查询数据,导致本异常。

       本文的系统所采用的架构为Hibernate4、Spring4、Struts2,客户端使用Ext JS4作为WEB界面框架,Ext JS4和Struts2交互使用JSON格式的数据,故使用了struts_json插件,Struts2的配置则采用convention插件,即注解的配置方式,Hibernate4采用JPA注解方式配置对象关系映射 ,先看一下POJO的关系映射

     1、MenuPanel,一的一方:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.mcs.user.pojo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.CascadeType;  
  7. import javax.persistence.Column;  
  8. import javax.persistence.Entity;  
  9. import javax.persistence.FetchType;  
  10. import javax.persistence.OneToMany;  
  11. import javax.persistence.Table;  
  12.   
  13. import org.hibernate.annotations.Columns;  
  14.   
  15. import com.mcs.pojo.base.GenericObject;  
  16.   
  17. @Entity  
  18. @Table(name = "MENUPANEL")  
  19. public class MenuPanel extends GenericObject {  
  20.     private String text;  
  21.     private List<Menu> menus=new ArrayList<Menu>();  
  22.   
  23.     public MenuPanel() {  
  24.     }  
  25.   
  26.     public MenuPanel(String text) {  
  27.         this.text = text;  
  28.     }  
  29.     public MenuPanel(long id,String text) {  
  30.         this.text = text;  
  31.         super.setId(id+"");  
  32.     }  
  33.   
  34.     public String getText() {  
  35.         return text;  
  36.     }  
  37.   
  38.     public void setText(String text) {  
  39.         this.text = text;  
  40.     }  
  41.   
  42.     @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY,mappedBy="menuPanel")  
  43.     public List<Menu> getMenus() {  
  44.         return menus;  
  45.     }  
  46.   
  47.     public void setMenus(List<Menu> menus) {  
  48.         this.menus = menus;  
  49.     }  
  50.   
  51. }  

      2、menu多的一方:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.mcs.user.pojo;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.persistence.CascadeType;  
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.JoinColumn;  
  10. import javax.persistence.ManyToOne;  
  11. import javax.persistence.OneToMany;  
  12. import javax.persistence.Table;  
  13. import static org.hibernate.annotations.CascadeType.SAVE_UPDATE;  
  14. import org.hibernate.annotations.Cascade;  
  15.   
  16. import com.mcs.pojo.base.GenericObject;  
  17.   
  18.   
  19. @Entity  
  20. @Table(name="MENU")  
  21. public class Menu extends GenericObject{  
  22.     private String text;  
  23.     private String url;  
  24.     private boolean leaf=true;//默认是叶子节点  
  25.     private MenuPanel menuPanel;  
  26.     private List<Menu> children;  
  27.     private Menu menu;  
  28.       
  29.       
  30.     public Menu() {  
  31.     }  
  32.   
  33.     public Menu(String text, String url) {  
  34.         super();  
  35.         this.text = text;  
  36.         this.url = url;  
  37.     }  
  38.     public Menu(long id,String text, String url,MenuPanel menuPanel) {  
  39.         super();  
  40.         super.setId(id+"");  
  41.         this.text = text;  
  42.         this.url = url;  
  43.         this.menuPanel=menuPanel;  
  44.     }  
  45.     public String getText() {  
  46.         return text;  
  47.     }  
  48.   
  49.     public void setText(String text) {  
  50.         this.text = text;  
  51.     }  
  52.   
  53.     public String getUrl() {  
  54.         return url;  
  55.     }  
  56.   
  57.     public void setUrl(String url) {  
  58.         this.url = url;  
  59.     }  
  60.   
  61.     @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class)  
  62.     @JoinColumn(name="menuPanelId",referencedColumnName="id",insertable=true,updatable=true)  
  63.     public MenuPanel getMenuPanel() {  
  64.         return menuPanel;  
  65.     }  
  66.   
  67.     public void setMenuPanel(MenuPanel menuPanel) {  
  68.         this.menuPanel = menuPanel;  
  69.     }  
  70.   
  71.     @Column(length=1000)  
  72.     public boolean isLeaf() {  
  73.         return leaf;  
  74.     }  
  75.   
  76.     public void setLeaf(boolean leaf) {  
  77.         this.leaf = leaf;  
  78.     }  
  79.   
  80.     @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="menu")  
  81.     public List<Menu> getChildren() {  
  82.         return children;  
  83.     }  
  84.   
  85.     public void setChildren(List<Menu> children) {  
  86.         this.children = children;  
  87.     }  
  88.   
  89.     @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class)  
  90.     @JoinColumn(name="parentId",referencedColumnName="id",insertable=true,updatable=true)  
  91.     public Menu getMenu() {  
  92.         return menu;  
  93.     }  
  94.   
  95.     public void setMenu(Menu menu) {  
  96.         this.menu = menu;  
  97.     }  
  98.       
  99.       
  100. }  

       manuPanel和menu是一对多的关系,manuPanel是一的一方,menu是多的一方,采用懒加载的方式,Struts2使用JSON插件进行JSON数据转换,配置如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @Action(value="queryMenu",results = { @Result(type = "json",params={"root","pageBean"})})  
  2.     public String queryMenu() {  
  3.           
  4.         menuPanels=menuPanelService.queryMenuPanel();  
  5.         this.pageBean.setRows(menuPanels);  
  6.         this.pageBean.setTotal(menuPanels.size());//不使用分页  
  7.         return "success";  
  8.     }  

        让Struts2支持Hibernate懒加载有三种方式,第一种:配置JSON插件需要排除的字段,第二种:使用DTO或者VO对象,可以解决懒加载的问题,并且可以有效减少不相关的调用,当然,在项目中使用DTO或VO对象,取决于项目架构的,我个人比较推崇使用DTO或者VO,但发现在项目组很难实行,第三种:修改JSON转换插件,可以彻底解决懒加的问题。咱们先介绍第一种:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @Action(value="queryMenu",results = { @Result(type = "json",params={"root","pageBean","excludeProperties","^.*menus$,^.*children$"})})  
  2.     public String queryMenu() {  
  3.           
  4.         menuPanels=menuPanelService.queryMenuPanel();  
  5.         this.pageBean.setRows(menuPanels);  
  6.         this.pageBean.setTotal(menuPanels.size());//不使用分页  
  7.         return "success";  
  8.     }  


 

        上面这个代码我们用的是正则表达式进行字段匹配,要排除多个字段,用逗号隔开。好了,现在不会报错了,数据也能加载了,但是如果我们有很多POJO类都使用懒加载,每次都要这么配置,简直就是一件痛苦的事,有没有一劳永逸的解决办法呢,答案是当然有,我们通过对JSON插件进行修改,让Struts2_JSON插件支持Hibernate懒加载,这样,就不用每次在Action中配置排除属性了,

      首先,在protected void bean(Object object)方法中的Object value = accessor.invoke(object);后面加入以下代码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Object value = accessor.invoke(object);  
  2. //如果是PersistentBag类型的实例,则是Hibernate的持久化对象  
  3. if (value instanceof PersistentBag) {  
  4.     // 判断bag对象是否已经初始化,如果没有初始化,则是懒加载的方式  
  5.     PersistentBag bag=(PersistentBag) value;  
  6.     boolean b=Hibernate.isInitialized(bag);  
  7.     if(b==false)  
  8.     {  
  9.         continue;                             
  10.     }  
  11. }  
  12. if (baseAccessor.isAnnotationPresent(JSONFieldBridge.class)) {....  


     然后将protected void value(Object object, Method method)方法中的LOG.debug("Cyclic reference detected on " + object);改为

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //将object改为取class类名,避免Hibernate懒加载错误  
  2. LOG.debug("Cyclic reference detected on " + clazz.getName());  

     完整代码如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * $Id: JSONWriter.java 1436290 2013-01-21 11:37:16Z lukaszlenart $ 
  3.  * 
  4.  * Licensed to the Apache Software Foundation (ASF) under one 
  5.  * or more contributor license agreements.  See the NOTICE file 
  6.  * distributed with this work for additional information 
  7.  * regarding copyright ownership.  The ASF licenses this file 
  8.  * to you under the Apache License, Version 2.0 (the 
  9.  * "License"); you may not use this file except in compliance 
  10.  * with the License.  You may obtain a copy of the License at 
  11.  * 
  12.  *  http://www.apache.org/licenses/LICENSE-2.0 
  13.  * 
  14.  * Unless required by applicable law or agreed to in writing, 
  15.  * software distributed under the License is distributed on an 
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
  17.  * KIND, either express or implied.  See the License for the 
  18.  * specific language governing permissions and limitations 
  19.  * under the License. 
  20.  */  
  21. package org.apache.struts2.json;  
  22.   
  23. import com.opensymphony.xwork2.util.logging.Logger;  
  24. import com.opensymphony.xwork2.util.logging.LoggerFactory;  
  25.   
  26. import org.apache.commons.beanutils.BeanUtils;  
  27. import org.apache.commons.beanutils.PropertyUtils;  
  28. import org.apache.commons.beanutils.PropertyUtilsBean;  
  29. import org.apache.struts2.json.annotations.JSON;  
  30. import org.apache.struts2.json.annotations.JSONFieldBridge;  
  31. import org.apache.struts2.json.annotations.JSONParameter;  
  32. import org.apache.struts2.json.bridge.FieldBridge;  
  33. import org.apache.struts2.json.bridge.ParameterizedBridge;  
  34. import org.apache.velocity.texen.util.PropertiesUtil;  
  35. import org.hibernate.Hibernate;  
  36. import org.hibernate.collection.internal.PersistentBag;  
  37.   
  38. import java.beans.BeanInfo;  
  39. import java.beans.IntrospectionException;  
  40. import java.beans.Introspector;  
  41. import java.beans.PropertyDescriptor;  
  42. import java.lang.reflect.Array;  
  43. import java.lang.reflect.Field;  
  44. import java.lang.reflect.Method;  
  45. import java.text.CharacterIterator;  
  46. import java.text.DateFormat;  
  47. import java.text.SimpleDateFormat;  
  48. import java.text.StringCharacterIterator;  
  49. import java.util.*;  
  50. import java.util.concurrent.ConcurrentHashMap;  
  51. import java.util.concurrent.ConcurrentMap;  
  52. import java.util.regex.Pattern;  
  53.   
  54. /** 
  55.  * <p> 
  56.  * Serializes an object into JavaScript Object Notation (JSON). If cyclic 
  57.  * references are detected they will be nulled out. 
  58.  * </p> 
  59.  */  
  60. public class JSONWriter {  
  61.   
  62.     private static final Logger LOG = LoggerFactory.getLogger(JSONWriter.class);  
  63.   
  64.     /** 
  65.      * By default, enums are serialised as name=value pairs 
  66.      */  
  67.     public static final boolean ENUM_AS_BEAN_DEFAULT = false;  
  68.   
  69.     private static char[] hex = "0123456789ABCDEF".toCharArray();  
  70.   
  71.     private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE_IGNORE_HIERARCHY = new ConcurrentHashMap<Class<?>, BeanInfo>();  
  72.     private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE = new ConcurrentHashMap<Class<?>, BeanInfo>();  
  73.   
  74.     private StringBuilder buf = new StringBuilder();  
  75.     private Stack<Object> stack = new Stack<Object>();  
  76.     private boolean ignoreHierarchy = true;  
  77.     private Object root;  
  78.     private boolean buildExpr = true;  
  79.     private String exprStack = "";  
  80.     private Collection<Pattern> excludeProperties;  
  81.     private Collection<Pattern> includeProperties;  
  82.     private DateFormat formatter;  
  83.     private boolean enumAsBean = ENUM_AS_BEAN_DEFAULT;  
  84.     private boolean excludeNullProperties;  
  85.   
  86.     /** 
  87.      * @param object 
  88.      *            Object to be serialized into JSON 
  89.      * @return JSON string for object 
  90.      * @throws JSONException 
  91.      */  
  92.     public String write(Object object) throws JSONException {  
  93.         return this.write(object, nullnullfalse);  
  94.     }  
  95.   
  96.     /** 
  97.      * @param object 
  98.      *            Object to be serialized into JSON 
  99.      * @return JSON string for object 
  100.      * @throws JSONException 
  101.      */  
  102.     public String write(Object object, Collection<Pattern> excludeProperties,  
  103.             Collection<Pattern> includeProperties, boolean excludeNullProperties)  
  104.             throws JSONException {  
  105.         this.excludeNullProperties = excludeNullProperties;  
  106.         this.buf.setLength(0);  
  107.         this.root = object;  
  108.         this.exprStack = "";  
  109.         this.buildExpr = ((excludeProperties != null) && !excludeProperties  
  110.                 .isEmpty())  
  111.                 || ((includeProperties != null) && !includeProperties.isEmpty());  
  112.         this.excludeProperties = excludeProperties;  
  113.         this.includeProperties = includeProperties;  
  114.         this.value(object, null);  
  115.   
  116.         return this.buf.toString();  
  117.     }  
  118.   
  119.     /** 
  120.      * Detect cyclic references 
  121.      */  
  122.     protected void value(Object object, Method method) throws JSONException {  
  123.         if (object == null) {  
  124.             this.add("null");  
  125.   
  126.             return;  
  127.         }  
  128.   
  129.         if (this.stack.contains(object)) {  
  130.             Class clazz = object.getClass();  
  131.   
  132.             // cyclic reference  
  133.             if (clazz.isPrimitive() || clazz.equals(String.class)) {  
  134.                 this.process(object, method);  
  135.             } else {  
  136.                 if (LOG.isDebugEnabled()) {  
  137.                     //将object改为取class类名,避免Hibernate懒加载错误  
  138.                     LOG.debug("Cyclic reference detected on " + clazz.getName());  
  139.                 }  
  140.                 this.add("null");  
  141.             }  
  142.   
  143.             return;  
  144.         }  
  145.   
  146.         this.process(object, method);  
  147.     }  
  148.   
  149.     /** 
  150.      * Serialize object into json 
  151.      */  
  152.     protected void process(Object object, Method method) throws JSONException {  
  153.         this.stack.push(object);  
  154.   
  155.         if (object instanceof Class) {  
  156.             this.string(object);  
  157.         } else if (object instanceof Boolean) {  
  158.             this.bool((Boolean) object);  
  159.         } else if (object instanceof Number) {  
  160.             this.add(object);  
  161.         } else if (object instanceof String) {  
  162.             this.string(object);  
  163.         } else if (object instanceof Character) {  
  164.             this.string(object);  
  165.         } else if (object instanceof Map) {  
  166.             this.map((Map) object, method);  
  167.         } else if (object.getClass().isArray()) {  
  168.             this.array(object, method);  
  169.         } else if (object instanceof Iterable) {  
  170.             this.array(((Iterable) object).iterator(), method);  
  171.         } else if (object instanceof Date) {  
  172.             this.date((Date) object, method);  
  173.         } else if (object instanceof Calendar) {  
  174.             this.date(((Calendar) object).getTime(), method);  
  175.         } else if (object instanceof Locale) {  
  176.             this.string(object);  
  177.         } else if (object instanceof Enum) {  
  178.             this.enumeration((Enum) object);  
  179.         } else {  
  180.             processCustom(object, method);  
  181.         }  
  182.   
  183.         this.stack.pop();  
  184.     }  
  185.   
  186.     /** 
  187.      * Serialize custom object into json 
  188.      */  
  189.     protected void processCustom(Object object, Method method)  
  190.             throws JSONException {  
  191.         this.bean(object);  
  192.     }  
  193.   
  194.     /** 
  195.      * Instrospect bean and serialize its properties 
  196.      */  
  197.     protected void bean(Object object) throws JSONException {  
  198.         this.add("{");  
  199.   
  200.         BeanInfo info;  
  201.   
  202.         try {  
  203.             Class clazz = object.getClass();  
  204.   
  205.             info = ((object == this.root) && this.ignoreHierarchy) ? getBeanInfoIgnoreHierarchy(clazz)  
  206.                     : getBeanInfo(clazz);  
  207.   
  208.             PropertyDescriptor[] props = info.getPropertyDescriptors();  
  209.   
  210.             boolean hasData = false;  
  211.             for (PropertyDescriptor prop : props) {  
  212.                 String name = prop.getName();  
  213.                 Method accessor = prop.getReadMethod();  
  214.                 Method baseAccessor = findBaseAccessor(clazz, accessor);  
  215.   
  216.                 if (baseAccessor != null) {  
  217.                     if (baseAccessor.isAnnotationPresent(JSON.class)) {  
  218.                         JSONAnnotationFinder jsonFinder = new JSONAnnotationFinder(  
  219.                                 baseAccessor).invoke();  
  220.   
  221.                         if (!jsonFinder.shouldSerialize())  
  222.                             continue;  
  223.                         if (jsonFinder.getName() != null) {  
  224.                             name = jsonFinder.getName();  
  225.                         }  
  226.                     }  
  227.                     // ignore "class" and others  
  228.                     if (this.shouldExcludeProperty(prop)) {  
  229.                         continue;  
  230.                     }  
  231.                     String expr = null;  
  232.                     if (this.buildExpr) {  
  233.                         expr = this.expandExpr(name);  
  234.                         if (this.shouldExcludeProperty(expr)) {  
  235.                             continue;  
  236.                         }  
  237.                         expr = this.setExprStack(expr);  
  238.                     }  
  239.   
  240.                     Object value = accessor.invoke(object);  
  241.                     //如果是PersistentBag类型的实例,则是Hibernate的持久化对象  
  242.                     if (value instanceof PersistentBag) {  
  243.                         // 判断bag对象是否已经初始化,如果没有初始化,则是懒加载的方式  
  244.                         PersistentBag bag=(PersistentBag) value;  
  245.                         boolean b=Hibernate.isInitialized(bag);  
  246.                         if(b==false)  
  247.                         {  
  248.                             continue;                             
  249.                         }  
  250.                     }  
  251.                     if (baseAccessor.isAnnotationPresent(JSONFieldBridge.class)) {  
  252.                         value = getBridgedValue(baseAccessor, value);  
  253.                     }  
  254.   
  255.                     boolean propertyPrinted = this.add(name, value, accessor,  
  256.                             hasData);  
  257.                     hasData = hasData || propertyPrinted;  
  258.                     if (this.buildExpr) {  
  259.                         this.setExprStack(expr);  
  260.                     }  
  261.                 }  
  262.             }  
  263.   
  264.             // special-case handling for an Enumeration - include the name() as  
  265.             // a property */  
  266.             if (object instanceof Enum) {  
  267.                 Object value = ((Enum) object).name();  
  268.                 this.add("_name", value, object.getClass().getMethod("name"),  
  269.                         hasData);  
  270.             }  
  271.         } catch (Exception e) {  
  272.             throw new JSONException(e);  
  273.         }  
  274.   
  275.         this.add("}");  
  276.     }  
  277.   
  278.     protected BeanInfo getBeanInfoIgnoreHierarchy(final Class<?> clazz)  
  279.             throws IntrospectionException {  
  280.         BeanInfo beanInfo = BEAN_INFO_CACHE_IGNORE_HIERARCHY.get(clazz);  
  281.         if (beanInfo != null) {  
  282.             return beanInfo;  
  283.         }  
  284.         beanInfo = Introspector.getBeanInfo(clazz, clazz.getSuperclass());  
  285.         BEAN_INFO_CACHE_IGNORE_HIERARCHY.put(clazz, beanInfo);  
  286.         return beanInfo;  
  287.     }  
  288.   
  289.     protected BeanInfo getBeanInfo(final Class<?> clazz)  
  290.             throws IntrospectionException {  
  291.         BeanInfo beanInfo = BEAN_INFO_CACHE.get(clazz);  
  292.         if (beanInfo != null) {  
  293.             return beanInfo;  
  294.         }  
  295.         beanInfo = Introspector.getBeanInfo(clazz);  
  296.         BEAN_INFO_CACHE.put(clazz, beanInfo);  
  297.         return beanInfo;  
  298.     }  
  299.   
  300.     protected Object getBridgedValue(Method baseAccessor, Object value)  
  301.             throws InstantiationException, IllegalAccessException {  
  302.         JSONFieldBridge fieldBridgeAnn = baseAccessor  
  303.                 .getAnnotation(JSONFieldBridge.class);  
  304.         if (fieldBridgeAnn != null) {  
  305.             Class impl = fieldBridgeAnn.impl();  
  306.             FieldBridge instance = (FieldBridge) impl.newInstance();  
  307.   
  308.             if (fieldBridgeAnn.params().length > 0  
  309.                     && ParameterizedBridge.class.isAssignableFrom(impl)) {  
  310.                 Map<String, String> params = new HashMap<String, String>(  
  311.                         fieldBridgeAnn.params().length);  
  312.                 for (JSONParameter param : fieldBridgeAnn.params()) {  
  313.                     params.put(param.name(), param.value());  
  314.                 }  
  315.                 ((ParameterizedBridge) instance).setParameterValues(params);  
  316.             }  
  317.             value = instance.objectToString(value);  
  318.         }  
  319.         return value;  
  320.     }  
  321.   
  322.     protected Method findBaseAccessor(Class clazz, Method accessor) {  
  323.         Method baseAccessor = null;  
  324.         if (clazz.getName().contains("
    EnhancerByCGLIB
    ")) {  
  325.             try {  
  326.                 baseAccessor = Thread.currentThread().getContextClassLoader()  
  327.                         .loadClass(  
  328.                                 clazz.getName().substring(0,  
  329.                                         clazz.getName().indexOf("$$")))  
  330.                         .getMethod(accessor.getName(),  
  331.                                 accessor.getParameterTypes());  
  332.             } catch (Exception ex) {  
  333.                 LOG.debug(ex.getMessage(), ex);  
  334.             }  
  335.         } else if (clazz.getName().contains("$$_javassist")) {  
  336.             try {  
  337.                 baseAccessor = Class.forName(  
  338.                         clazz.getName().substring(0,  
  339.                                 clazz.getName().indexOf("_$$"))).getMethod(  
  340.                         accessor.getName(), accessor.getParameterTypes());  
  341.             } catch (Exception ex) {  
  342.                 LOG.debug(ex.getMessage(), ex);  
  343.             }  
  344.         } else {  
  345.             return accessor;  
  346.         }  
  347.         return baseAccessor;  
  348.     }  
  349.   
  350.     /** 
  351.      * Instrospect an Enum and serialize it as a name/value pair or as a bean 
  352.      * including all its own properties 
  353.      */  
  354.     protected void enumeration(Enum enumeration) throws JSONException {  
  355.         if (enumAsBean) {  
  356.             this.bean(enumeration);  
  357.         } else {  
  358.             this.string(enumeration.name());  
  359.         }  
  360.     }  
  361.   
  362.     protected boolean shouldExcludeProperty(PropertyDescriptor prop)  
  363.             throws SecurityException, NoSuchFieldException {  
  364.         String name = prop.getName();  
  365.         return name.equals("class") || name.equals("declaringClass")  
  366.                 || name.equals("cachedSuperClass") || name.equals("metaClass");  
  367.     }  
  368.   
  369.     protected String expandExpr(int i) {  
  370.         return this.exprStack + "[" + i + "]";  
  371.     }  
  372.   
  373.     protected String expandExpr(String property) {  
  374.         if (this.exprStack.length() == 0) {  
  375.             return property;  
  376.         }  
  377.         return this.exprStack + "." + property;  
  378.     }  
  379.   
  380.     protected String setExprStack(String expr) {  
  381.         String s = this.exprStack;  
  382.         this.exprStack = expr;  
  383.         return s;  
  384.     }  
  385.   
  386.     protected boolean shouldExcludeProperty(String expr) {  
  387.         if (this.excludeProperties != null) {  
  388.             for (Pattern pattern : this.excludeProperties) {  
  389.                 if (pattern.matcher(expr).matches()) {  
  390.                     if (LOG.isDebugEnabled()) {  
  391.                         LOG.debug("Ignoring property because of exclude rule: "  
  392.                                 + expr);  
  393.                     }  
  394.                     return true;  
  395.                 }  
  396.             }  
  397.         }  
  398.   
  399.         if (this.includeProperties != null) {  
  400.             for (Pattern pattern : this.includeProperties) {  
  401.                 if (pattern.matcher(expr).matches()) {  
  402.                     return false;  
  403.                 }  
  404.             }  
  405.             if (LOG.isDebugEnabled()) {  
  406.                 LOG  
  407.                         .debug("Ignoring property because of include rule:  "  
  408.                                 + expr);  
  409.             }  
  410.             return true;  
  411.         }  
  412.         return false;  
  413.     }  
  414.   
  415.     /** 
  416.      * Add name/value pair to buffer 
  417.      */  
  418.     protected boolean add(String name, Object value, Method method,  
  419.             boolean hasData) throws JSONException {  
  420.         if (excludeNullProperties && value == null) {  
  421.             return false;  
  422.         }  
  423.         if (hasData) {  
  424.             this.add(',');  
  425.         }  
  426.         this.add('"');  
  427.         this.add(name);  
  428.         this.add("\":");  
  429.         this.value(value, method);  
  430.         return true;  
  431.     }  
  432.   
  433.     /** 
  434.      * Add map to buffer 
  435.      */  
  436.     protected void map(Map map, Method method) throws JSONException {  
  437.         this.add("{");  
  438.   
  439.         Iterator it = map.entrySet().iterator();  
  440.   
  441.         boolean warnedNonString = false// one report per map  
  442.         boolean hasData = false;  
  443.         while (it.hasNext()) {  
  444.             Map.Entry entry = (Map.Entry) it.next();  
  445.             if (excludeNullProperties && entry.getValue() == null) {  
  446.                 continue;  
  447.             }  
  448.   
  449.             Object key = entry.getKey();  
  450.             if (key == null) {  
  451.                 LOG.error("Cannot build expression for null key in #0",  
  452.                         exprStack);  
  453.                 continue;  
  454.             }  
  455.   
  456.             String expr = null;  
  457.             if (this.buildExpr) {  
  458.                 expr = this.expandExpr(key.toString());  
  459.                 if (this.shouldExcludeProperty(expr)) {  
  460.                     continue;  
  461.                 }  
  462.                 expr = this.setExprStack(expr);  
  463.             }  
  464.             if (hasData) {  
  465.                 this.add(',');  
  466.             }  
  467.             hasData = true;  
  468.             if (!warnedNonString && !(key instanceof String)) {  
  469.                 if (LOG.isWarnEnabled()) {  
  470.                     LOG  
  471.                             .warn(  
  472.                                     "JavaScript doesn't support non-String keys, using toString() on #0",  
  473.                                     key.getClass().getName());  
  474.                 }  
  475.                 warnedNonString = true;  
  476.             }  
  477.             this.value(key.toString(), method);  
  478.             this.add(":");  
  479.             this.value(entry.getValue(), method);  
  480.             if (this.buildExpr) {  
  481.                 this.setExprStack(expr);  
  482.             }  
  483.         }  
  484.   
  485.         this.add("}");  
  486.     }  
  487.   
  488.     /** 
  489.      * Add date to buffer 
  490.      */  
  491.     protected void date(Date date, Method method) {  
  492.         JSON json = null;  
  493.         if (method != null)  
  494.             json = method.getAnnotation(JSON.class);  
  495.         if (this.formatter == null)  
  496.             this.formatter = new SimpleDateFormat(JSONUtil.RFC3339_FORMAT);  
  497.   
  498.         DateFormat formatter = (json != null) && (json.format().length() > 0) ? new SimpleDateFormat(  
  499.                 json.format())  
  500.                 : this.formatter;  
  501.         this.string(formatter.format(date));  
  502.     }  
  503.   
  504.     /** 
  505.      * Add array to buffer 
  506.      */  
  507.     protected void array(Iterator it, Method method) throws JSONException {  
  508.         this.add("[");  
  509.   
  510.         boolean hasData = false;  
  511.         for (int i = 0; it.hasNext(); i++) {  
  512.             String expr = null;  
  513.             if (this.buildExpr) {  
  514.                 expr = this.expandExpr(i);  
  515.                 if (this.shouldExcludeProperty(expr)) {  
  516.                     it.next();  
  517.                     continue;  
  518.                 }  
  519.                 expr = this.setExprStack(expr);  
  520.             }  
  521.             if (hasData) {  
  522.                 this.add(',');  
  523.             }  
  524.             hasData = true;  
  525.             this.value(it.next(), method);  
  526.             if (this.buildExpr) {  
  527.                 this.setExprStack(expr);  
  528.             }  
  529.         }  
  530.   
  531.         this.add("]");  
  532.     }  
  533.   
  534.     /** 
  535.      * Add array to buffer 
  536.      */  
  537.     protected void array(Object object, Method method) throws JSONException {  
  538.         this.add("[");  
  539.   
  540.         int length = Array.getLength(object);  
  541.   
  542.         boolean hasData = false;  
  543.         for (int i = 0; i < length; ++i) {  
  544.             String expr = null;  
  545.             if (this.buildExpr) {  
  546.                 expr = this.expandExpr(i);  
  547.                 if (this.shouldExcludeProperty(expr)) {  
  548.                     continue;  
  549.                 }  
  550.                 expr = this.setExprStack(expr);  
  551.             }  
  552.             if (hasData) {  
  553.                 this.add(',');  
  554.             }  
  555.             hasData = true;  
  556.             this.value(Array.get(object, i), method);  
  557.             if (this.buildExpr) {  
  558.                 this.setExprStack(expr);  
  559.             }  
  560.         }  
  561.   
  562.         this.add("]");  
  563.     }  
  564.   
  565.     /** 
  566.      * Add boolean to buffer 
  567.      */  
  568.     protected void bool(boolean b) {  
  569.         this.add(b ? "true" : "false");  
  570.     }  
  571.   
  572.     /** 
  573.      * escape characters 
  574.      */  
  575.     protected void string(Object obj) {  
  576.         this.add('"');  
  577.   
  578.         CharacterIterator it = new StringCharacterIterator(obj.toString());  
  579.   
  580.         for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {  
  581.             if (c == '"') {  
  582.                 this.add("\\\"");  
  583.             } else if (c == '\\') {  
  584.                 this.add("\\\\");  
  585.             } else if (c == '/') {  
  586.                 this.add("\\/");  
  587.             } else if (c == '\b') {  
  588.                 this.add("\\b");  
  589.             } else if (c == '\f') {  
  590.                 this.add("\\f");  
  591.             } else if (c == '\n') {  
  592.                 this.add("\\n");  
  593.             } else if (c == '\r') {  
  594.                 this.add("\\r");  
  595.             } else if (c == '\t') {  
  596.                 this.add("\\t");  
  597.             } else if (Character.isISOControl(c)) {  
  598.                 this.unicode(c);  
  599.             } else {  
  600.                 this.add(c);  
  601.             }  
  602.         }  
  603.   
  604.         this.add('"');  
  605.     }  
  606.   
  607.     /** 
  608.      * Add object to buffer 
  609.      */  
  610.     protected void add(Object obj) {  
  611.         this.buf.append(obj);  
  612.     }  
  613.   
  614.     /** 
  615.      * Add char to buffer 
  616.      */  
  617.     protected void add(char c) {  
  618.         this.buf.append(c);  
  619.     }  
  620.   
  621.     /** 
  622.      * Represent as unicode 
  623.      *  
  624.      * @param c 
  625.      *            character to be encoded 
  626.      */  
  627.     protected void unicode(char c) {  
  628.         this.add("\\u");  
  629.   
  630.         int n = c;  
  631.   
  632.         for (int i = 0; i < 4; ++i) {  
  633.             int digit = (n & 0xf000) >> 12;  
  634.   
  635.             this.add(hex[digit]);  
  636.             n <<= 4;  
  637.         }  
  638.     }  
  639.   
  640.     public void setIgnoreHierarchy(boolean ignoreHierarchy) {  
  641.         this.ignoreHierarchy = ignoreHierarchy;  
  642.     }  
  643.   
  644.     /** 
  645.      * If true, an Enum is serialized as a bean with a special property 
  646.      * _name=name() as all as all other properties defined within the enum.<br/> 
  647.      * If false, an Enum is serialized as a name=value pair (name=name()) 
  648.      *  
  649.      * @param enumAsBean 
  650.      *            true to serialize an enum as a bean instead of as a name=value 
  651.      *            pair (default=false) 
  652.      */  
  653.     public void setEnumAsBean(boolean enumAsBean) {  
  654.         this.enumAsBean = enumAsBean;  
  655.     }  
  656.   
  657.     protected static class JSONAnnotationFinder {  
  658.         private boolean serialize = true;  
  659.         private Method accessor;  
  660.         private String name;  
  661.   
  662.         public JSONAnnotationFinder(Method accessor) {  
  663.             this.accessor = accessor;  
  664.         }  
  665.   
  666.         public boolean shouldSerialize() {  
  667.             return serialize;  
  668.         }  
  669.   
  670.         public String getName() {  
  671.             return name;  
  672.         }  
  673.   
  674.         public JSONAnnotationFinder invoke() {  
  675.             JSON json = accessor.getAnnotation(JSON.class);  
  676.             serialize = json.serialize();  
  677.             if (serialize && json.name().length() > 0) {  
  678.                 name = json.name();  
  679.             }  
  680.             return this;  
  681.         }  
  682.     }  
  683.   
  684. }  


      在你的工程中新建org.apache.struts2.json包,把以上代码复制到你的工程里就可以了,要注意的是,如果是在WEBLOGIC中部署,最好把这个类重新打包到struts2-json-plugin-2.3.15.3.jar包中,避免不必要的麻烦。

0 0
原创粉丝点击