彻底解决SSH架构中的Hibernate懒加载问题
来源:互联网 发布:mysql 网易镜像 编辑:程序博客网 时间:2024/05/07 15:34
在客户端使用AJAX框架,服务端采用Struts2+Spring+Hibernate的架构中,经常会遇到Hibernate懒加载的问题 ,异常为:
- org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role
相信大家经常可以在网上看到相关的技术文章,大致是在web.xml中加上openSessionFilter,代码如下:
- <filter>
- <filter-name>hibernateFilter</filter-name>
- <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
- </filter>
如果你真的亲自去写代码了,你会发现这个方法根本不管用,原因在于Struts2的JSON插件使用反射技术,会调用关联对象的get方法获取对象的实例,从而触发Hibernate查询数据,导致本异常。
本文的系统所采用的架构为Hibernate4、Spring4、Struts2,客户端使用Ext JS4作为WEB界面框架,Ext JS4和Struts2交互使用JSON格式的数据,故使用了struts_json插件,Struts2的配置则采用convention插件,即注解的配置方式,Hibernate4采用JPA注解方式配置对象关系映射 ,先看一下POJO的关系映射
1、MenuPanel,一的一方:
- package com.mcs.user.pojo;
- import java.util.ArrayList;
- import java.util.List;
- import javax.persistence.CascadeType;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.FetchType;
- import javax.persistence.OneToMany;
- import javax.persistence.Table;
- import org.hibernate.annotations.Columns;
- import com.mcs.pojo.base.GenericObject;
- @Entity
- @Table(name = "MENUPANEL")
- public class MenuPanel extends GenericObject {
- private String text;
- private List<Menu> menus=new ArrayList<Menu>();
- public MenuPanel() {
- }
- public MenuPanel(String text) {
- this.text = text;
- }
- public MenuPanel(long id,String text) {
- this.text = text;
- super.setId(id+"");
- }
- public String getText() {
- return text;
- }
- public void setText(String text) {
- this.text = text;
- }
- @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY,mappedBy="menuPanel")
- public List<Menu> getMenus() {
- return menus;
- }
- public void setMenus(List<Menu> menus) {
- this.menus = menus;
- }
- }
2、menu多的一方:
- package com.mcs.user.pojo;
- import java.util.List;
- import javax.persistence.CascadeType;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.FetchType;
- import javax.persistence.JoinColumn;
- import javax.persistence.ManyToOne;
- import javax.persistence.OneToMany;
- import javax.persistence.Table;
- import static org.hibernate.annotations.CascadeType.SAVE_UPDATE;
- import org.hibernate.annotations.Cascade;
- import com.mcs.pojo.base.GenericObject;
- @Entity
- @Table(name="MENU")
- public class Menu extends GenericObject{
- private String text;
- private String url;
- private boolean leaf=true;//默认是叶子节点
- private MenuPanel menuPanel;
- private List<Menu> children;
- private Menu menu;
- public Menu() {
- }
- public Menu(String text, String url) {
- super();
- this.text = text;
- this.url = url;
- }
- public Menu(long id,String text, String url,MenuPanel menuPanel) {
- super();
- super.setId(id+"");
- this.text = text;
- this.url = url;
- this.menuPanel=menuPanel;
- }
- public String getText() {
- return text;
- }
- public void setText(String text) {
- this.text = text;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class)
- @JoinColumn(name="menuPanelId",referencedColumnName="id",insertable=true,updatable=true)
- public MenuPanel getMenuPanel() {
- return menuPanel;
- }
- public void setMenuPanel(MenuPanel menuPanel) {
- this.menuPanel = menuPanel;
- }
- @Column(length=1000)
- public boolean isLeaf() {
- return leaf;
- }
- public void setLeaf(boolean leaf) {
- this.leaf = leaf;
- }
- @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="menu")
- public List<Menu> getChildren() {
- return children;
- }
- public void setChildren(List<Menu> children) {
- this.children = children;
- }
- @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class)
- @JoinColumn(name="parentId",referencedColumnName="id",insertable=true,updatable=true)
- public Menu getMenu() {
- return menu;
- }
- public void setMenu(Menu menu) {
- this.menu = menu;
- }
- }
manuPanel和menu是一对多的关系,manuPanel是一的一方,menu是多的一方,采用懒加载的方式,Struts2使用JSON插件进行JSON数据转换,配置如下
- @Action(value="queryMenu",results = { @Result(type = "json",params={"root","pageBean"})})
- public String queryMenu() {
- menuPanels=menuPanelService.queryMenuPanel();
- this.pageBean.setRows(menuPanels);
- this.pageBean.setTotal(menuPanels.size());//不使用分页
- return "success";
- }
让Struts2支持Hibernate懒加载有三种方式,第一种:配置JSON插件需要排除的字段,第二种:使用DTO或者VO对象,可以解决懒加载的问题,并且可以有效减少不相关的调用,当然,在项目中使用DTO或VO对象,取决于项目架构的,我个人比较推崇使用DTO或者VO,但发现在项目组很难实行,第三种:修改JSON转换插件,可以彻底解决懒加的问题。咱们先介绍第一种:
- @Action(value="queryMenu",results = { @Result(type = "json",params={"root","pageBean","excludeProperties","^.*menus$,^.*children$"})})
- public String queryMenu() {
- menuPanels=menuPanelService.queryMenuPanel();
- this.pageBean.setRows(menuPanels);
- this.pageBean.setTotal(menuPanels.size());//不使用分页
- return "success";
- }
上面这个代码我们用的是正则表达式进行字段匹配,要排除多个字段,用逗号隔开。好了,现在不会报错了,数据也能加载了,但是如果我们有很多POJO类都使用懒加载,每次都要这么配置,简直就是一件痛苦的事,有没有一劳永逸的解决办法呢,答案是当然有,我们通过对JSON插件进行修改,让Struts2_JSON插件支持Hibernate懒加载,这样,就不用每次在Action中配置排除属性了,
首先,在protected void bean(Object object)方法中的Object value = accessor.invoke(object);后面加入以下代码
- Object value = accessor.invoke(object);
- //如果是PersistentBag类型的实例,则是Hibernate的持久化对象
- if (value instanceof PersistentBag) {
- // 判断bag对象是否已经初始化,如果没有初始化,则是懒加载的方式
- PersistentBag bag=(PersistentBag) value;
- boolean b=Hibernate.isInitialized(bag);
- if(b==false)
- {
- continue;
- }
- }
- if (baseAccessor.isAnnotationPresent(JSONFieldBridge.class)) {....
然后将protected void value(Object object, Method method)方法中的LOG.debug("Cyclic reference detected on " + object);改为
- //将object改为取class类名,避免Hibernate懒加载错误
- LOG.debug("Cyclic reference detected on " + clazz.getName());
完整代码如下:
- /*
- * $Id: JSONWriter.java 1436290 2013-01-21 11:37:16Z lukaszlenart $
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
- package org.apache.struts2.json;
- import com.opensymphony.xwork2.util.logging.Logger;
- import com.opensymphony.xwork2.util.logging.LoggerFactory;
- import org.apache.commons.beanutils.BeanUtils;
- import org.apache.commons.beanutils.PropertyUtils;
- import org.apache.commons.beanutils.PropertyUtilsBean;
- import org.apache.struts2.json.annotations.JSON;
- import org.apache.struts2.json.annotations.JSONFieldBridge;
- import org.apache.struts2.json.annotations.JSONParameter;
- import org.apache.struts2.json.bridge.FieldBridge;
- import org.apache.struts2.json.bridge.ParameterizedBridge;
- import org.apache.velocity.texen.util.PropertiesUtil;
- import org.hibernate.Hibernate;
- import org.hibernate.collection.internal.PersistentBag;
- import java.beans.BeanInfo;
- import java.beans.IntrospectionException;
- import java.beans.Introspector;
- import java.beans.PropertyDescriptor;
- import java.lang.reflect.Array;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.text.CharacterIterator;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.text.StringCharacterIterator;
- import java.util.*;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.regex.Pattern;
- /**
- * <p>
- * Serializes an object into JavaScript Object Notation (JSON). If cyclic
- * references are detected they will be nulled out.
- * </p>
- */
- public class JSONWriter {
- private static final Logger LOG = LoggerFactory.getLogger(JSONWriter.class);
- /**
- * By default, enums are serialised as name=value pairs
- */
- public static final boolean ENUM_AS_BEAN_DEFAULT = false;
- private static char[] hex = "0123456789ABCDEF".toCharArray();
- private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE_IGNORE_HIERARCHY = new ConcurrentHashMap<Class<?>, BeanInfo>();
- private static final ConcurrentMap<Class<?>, BeanInfo> BEAN_INFO_CACHE = new ConcurrentHashMap<Class<?>, BeanInfo>();
- private StringBuilder buf = new StringBuilder();
- private Stack<Object> stack = new Stack<Object>();
- private boolean ignoreHierarchy = true;
- private Object root;
- private boolean buildExpr = true;
- private String exprStack = "";
- private Collection<Pattern> excludeProperties;
- private Collection<Pattern> includeProperties;
- private DateFormat formatter;
- private boolean enumAsBean = ENUM_AS_BEAN_DEFAULT;
- private boolean excludeNullProperties;
- /**
- * @param object
- * Object to be serialized into JSON
- * @return JSON string for object
- * @throws JSONException
- */
- public String write(Object object) throws JSONException {
- return this.write(object, null, null, false);
- }
- /**
- * @param object
- * Object to be serialized into JSON
- * @return JSON string for object
- * @throws JSONException
- */
- public String write(Object object, Collection<Pattern> excludeProperties,
- Collection<Pattern> includeProperties, boolean excludeNullProperties)
- throws JSONException {
- this.excludeNullProperties = excludeNullProperties;
- this.buf.setLength(0);
- this.root = object;
- this.exprStack = "";
- this.buildExpr = ((excludeProperties != null) && !excludeProperties
- .isEmpty())
- || ((includeProperties != null) && !includeProperties.isEmpty());
- this.excludeProperties = excludeProperties;
- this.includeProperties = includeProperties;
- this.value(object, null);
- return this.buf.toString();
- }
- /**
- * Detect cyclic references
- */
- protected void value(Object object, Method method) throws JSONException {
- if (object == null) {
- this.add("null");
- return;
- }
- if (this.stack.contains(object)) {
- Class clazz = object.getClass();
- // cyclic reference
- if (clazz.isPrimitive() || clazz.equals(String.class)) {
- this.process(object, method);
- } else {
- if (LOG.isDebugEnabled()) {
- //将object改为取class类名,避免Hibernate懒加载错误
- LOG.debug("Cyclic reference detected on " + clazz.getName());
- }
- this.add("null");
- }
- return;
- }
- this.process(object, method);
- }
- /**
- * Serialize object into json
- */
- protected void process(Object object, Method method) throws JSONException {
- this.stack.push(object);
- if (object instanceof Class) {
- this.string(object);
- } else if (object instanceof Boolean) {
- this.bool((Boolean) object);
- } else if (object instanceof Number) {
- this.add(object);
- } else if (object instanceof String) {
- this.string(object);
- } else if (object instanceof Character) {
- this.string(object);
- } else if (object instanceof Map) {
- this.map((Map) object, method);
- } else if (object.getClass().isArray()) {
- this.array(object, method);
- } else if (object instanceof Iterable) {
- this.array(((Iterable) object).iterator(), method);
- } else if (object instanceof Date) {
- this.date((Date) object, method);
- } else if (object instanceof Calendar) {
- this.date(((Calendar) object).getTime(), method);
- } else if (object instanceof Locale) {
- this.string(object);
- } else if (object instanceof Enum) {
- this.enumeration((Enum) object);
- } else {
- processCustom(object, method);
- }
- this.stack.pop();
- }
- /**
- * Serialize custom object into json
- */
- protected void processCustom(Object object, Method method)
- throws JSONException {
- this.bean(object);
- }
- /**
- * Instrospect bean and serialize its properties
- */
- protected void bean(Object object) throws JSONException {
- this.add("{");
- BeanInfo info;
- try {
- Class clazz = object.getClass();
- info = ((object == this.root) && this.ignoreHierarchy) ? getBeanInfoIgnoreHierarchy(clazz)
- : getBeanInfo(clazz);
- PropertyDescriptor[] props = info.getPropertyDescriptors();
- boolean hasData = false;
- for (PropertyDescriptor prop : props) {
- String name = prop.getName();
- Method accessor = prop.getReadMethod();
- Method baseAccessor = findBaseAccessor(clazz, accessor);
- if (baseAccessor != null) {
- if (baseAccessor.isAnnotationPresent(JSON.class)) {
- JSONAnnotationFinder jsonFinder = new JSONAnnotationFinder(
- baseAccessor).invoke();
- if (!jsonFinder.shouldSerialize())
- continue;
- if (jsonFinder.getName() != null) {
- name = jsonFinder.getName();
- }
- }
- // ignore "class" and others
- if (this.shouldExcludeProperty(prop)) {
- continue;
- }
- String expr = null;
- if (this.buildExpr) {
- expr = this.expandExpr(name);
- if (this.shouldExcludeProperty(expr)) {
- continue;
- }
- expr = this.setExprStack(expr);
- }
- Object value = accessor.invoke(object);
- //如果是PersistentBag类型的实例,则是Hibernate的持久化对象
- if (value instanceof PersistentBag) {
- // 判断bag对象是否已经初始化,如果没有初始化,则是懒加载的方式
- PersistentBag bag=(PersistentBag) value;
- boolean b=Hibernate.isInitialized(bag);
- if(b==false)
- {
- continue;
- }
- }
- if (baseAccessor.isAnnotationPresent(JSONFieldBridge.class)) {
- value = getBridgedValue(baseAccessor, value);
- }
- boolean propertyPrinted = this.add(name, value, accessor,
- hasData);
- hasData = hasData || propertyPrinted;
- if (this.buildExpr) {
- this.setExprStack(expr);
- }
- }
- }
- // special-case handling for an Enumeration - include the name() as
- // a property */
- if (object instanceof Enum) {
- Object value = ((Enum) object).name();
- this.add("_name", value, object.getClass().getMethod("name"),
- hasData);
- }
- } catch (Exception e) {
- throw new JSONException(e);
- }
- this.add("}");
- }
- protected BeanInfo getBeanInfoIgnoreHierarchy(final Class<?> clazz)
- throws IntrospectionException {
- BeanInfo beanInfo = BEAN_INFO_CACHE_IGNORE_HIERARCHY.get(clazz);
- if (beanInfo != null) {
- return beanInfo;
- }
- beanInfo = Introspector.getBeanInfo(clazz, clazz.getSuperclass());
- BEAN_INFO_CACHE_IGNORE_HIERARCHY.put(clazz, beanInfo);
- return beanInfo;
- }
- protected BeanInfo getBeanInfo(final Class<?> clazz)
- throws IntrospectionException {
- BeanInfo beanInfo = BEAN_INFO_CACHE.get(clazz);
- if (beanInfo != null) {
- return beanInfo;
- }
- beanInfo = Introspector.getBeanInfo(clazz);
- BEAN_INFO_CACHE.put(clazz, beanInfo);
- return beanInfo;
- }
- protected Object getBridgedValue(Method baseAccessor, Object value)
- throws InstantiationException, IllegalAccessException {
- JSONFieldBridge fieldBridgeAnn = baseAccessor
- .getAnnotation(JSONFieldBridge.class);
- if (fieldBridgeAnn != null) {
- Class impl = fieldBridgeAnn.impl();
- FieldBridge instance = (FieldBridge) impl.newInstance();
- if (fieldBridgeAnn.params().length > 0
- && ParameterizedBridge.class.isAssignableFrom(impl)) {
- Map<String, String> params = new HashMap<String, String>(
- fieldBridgeAnn.params().length);
- for (JSONParameter param : fieldBridgeAnn.params()) {
- params.put(param.name(), param.value());
- }
- ((ParameterizedBridge) instance).setParameterValues(params);
- }
- value = instance.objectToString(value);
- }
- return value;
- }
- protected Method findBaseAccessor(Class clazz, Method accessor) {
- Method baseAccessor = null;
- if (clazz.getName().contains("")) {
EnhancerByCGLIB - try {
- baseAccessor = Thread.currentThread().getContextClassLoader()
- .loadClass(
- clazz.getName().substring(0,
- clazz.getName().indexOf("$$")))
- .getMethod(accessor.getName(),
- accessor.getParameterTypes());
- } catch (Exception ex) {
- LOG.debug(ex.getMessage(), ex);
- }
- } else if (clazz.getName().contains("$$_javassist")) {
- try {
- baseAccessor = Class.forName(
- clazz.getName().substring(0,
- clazz.getName().indexOf("_$$"))).getMethod(
- accessor.getName(), accessor.getParameterTypes());
- } catch (Exception ex) {
- LOG.debug(ex.getMessage(), ex);
- }
- } else {
- return accessor;
- }
- return baseAccessor;
- }
- /**
- * Instrospect an Enum and serialize it as a name/value pair or as a bean
- * including all its own properties
- */
- protected void enumeration(Enum enumeration) throws JSONException {
- if (enumAsBean) {
- this.bean(enumeration);
- } else {
- this.string(enumeration.name());
- }
- }
- protected boolean shouldExcludeProperty(PropertyDescriptor prop)
- throws SecurityException, NoSuchFieldException {
- String name = prop.getName();
- return name.equals("class") || name.equals("declaringClass")
- || name.equals("cachedSuperClass") || name.equals("metaClass");
- }
- protected String expandExpr(int i) {
- return this.exprStack + "[" + i + "]";
- }
- protected String expandExpr(String property) {
- if (this.exprStack.length() == 0) {
- return property;
- }
- return this.exprStack + "." + property;
- }
- protected String setExprStack(String expr) {
- String s = this.exprStack;
- this.exprStack = expr;
- return s;
- }
- protected boolean shouldExcludeProperty(String expr) {
- if (this.excludeProperties != null) {
- for (Pattern pattern : this.excludeProperties) {
- if (pattern.matcher(expr).matches()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Ignoring property because of exclude rule: "
- + expr);
- }
- return true;
- }
- }
- }
- if (this.includeProperties != null) {
- for (Pattern pattern : this.includeProperties) {
- if (pattern.matcher(expr).matches()) {
- return false;
- }
- }
- if (LOG.isDebugEnabled()) {
- LOG
- .debug("Ignoring property because of include rule: "
- + expr);
- }
- return true;
- }
- return false;
- }
- /**
- * Add name/value pair to buffer
- */
- protected boolean add(String name, Object value, Method method,
- boolean hasData) throws JSONException {
- if (excludeNullProperties && value == null) {
- return false;
- }
- if (hasData) {
- this.add(',');
- }
- this.add('"');
- this.add(name);
- this.add("\":");
- this.value(value, method);
- return true;
- }
- /**
- * Add map to buffer
- */
- protected void map(Map map, Method method) throws JSONException {
- this.add("{");
- Iterator it = map.entrySet().iterator();
- boolean warnedNonString = false; // one report per map
- boolean hasData = false;
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- if (excludeNullProperties && entry.getValue() == null) {
- continue;
- }
- Object key = entry.getKey();
- if (key == null) {
- LOG.error("Cannot build expression for null key in #0",
- exprStack);
- continue;
- }
- String expr = null;
- if (this.buildExpr) {
- expr = this.expandExpr(key.toString());
- if (this.shouldExcludeProperty(expr)) {
- continue;
- }
- expr = this.setExprStack(expr);
- }
- if (hasData) {
- this.add(',');
- }
- hasData = true;
- if (!warnedNonString && !(key instanceof String)) {
- if (LOG.isWarnEnabled()) {
- LOG
- .warn(
- "JavaScript doesn't support non-String keys, using toString() on #0",
- key.getClass().getName());
- }
- warnedNonString = true;
- }
- this.value(key.toString(), method);
- this.add(":");
- this.value(entry.getValue(), method);
- if (this.buildExpr) {
- this.setExprStack(expr);
- }
- }
- this.add("}");
- }
- /**
- * Add date to buffer
- */
- protected void date(Date date, Method method) {
- JSON json = null;
- if (method != null)
- json = method.getAnnotation(JSON.class);
- if (this.formatter == null)
- this.formatter = new SimpleDateFormat(JSONUtil.RFC3339_FORMAT);
- DateFormat formatter = (json != null) && (json.format().length() > 0) ? new SimpleDateFormat(
- json.format())
- : this.formatter;
- this.string(formatter.format(date));
- }
- /**
- * Add array to buffer
- */
- protected void array(Iterator it, Method method) throws JSONException {
- this.add("[");
- boolean hasData = false;
- for (int i = 0; it.hasNext(); i++) {
- String expr = null;
- if (this.buildExpr) {
- expr = this.expandExpr(i);
- if (this.shouldExcludeProperty(expr)) {
- it.next();
- continue;
- }
- expr = this.setExprStack(expr);
- }
- if (hasData) {
- this.add(',');
- }
- hasData = true;
- this.value(it.next(), method);
- if (this.buildExpr) {
- this.setExprStack(expr);
- }
- }
- this.add("]");
- }
- /**
- * Add array to buffer
- */
- protected void array(Object object, Method method) throws JSONException {
- this.add("[");
- int length = Array.getLength(object);
- boolean hasData = false;
- for (int i = 0; i < length; ++i) {
- String expr = null;
- if (this.buildExpr) {
- expr = this.expandExpr(i);
- if (this.shouldExcludeProperty(expr)) {
- continue;
- }
- expr = this.setExprStack(expr);
- }
- if (hasData) {
- this.add(',');
- }
- hasData = true;
- this.value(Array.get(object, i), method);
- if (this.buildExpr) {
- this.setExprStack(expr);
- }
- }
- this.add("]");
- }
- /**
- * Add boolean to buffer
- */
- protected void bool(boolean b) {
- this.add(b ? "true" : "false");
- }
- /**
- * escape characters
- */
- protected void string(Object obj) {
- this.add('"');
- CharacterIterator it = new StringCharacterIterator(obj.toString());
- for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
- if (c == '"') {
- this.add("\\\"");
- } else if (c == '\\') {
- this.add("\\\\");
- } else if (c == '/') {
- this.add("\\/");
- } else if (c == '\b') {
- this.add("\\b");
- } else if (c == '\f') {
- this.add("\\f");
- } else if (c == '\n') {
- this.add("\\n");
- } else if (c == '\r') {
- this.add("\\r");
- } else if (c == '\t') {
- this.add("\\t");
- } else if (Character.isISOControl(c)) {
- this.unicode(c);
- } else {
- this.add(c);
- }
- }
- this.add('"');
- }
- /**
- * Add object to buffer
- */
- protected void add(Object obj) {
- this.buf.append(obj);
- }
- /**
- * Add char to buffer
- */
- protected void add(char c) {
- this.buf.append(c);
- }
- /**
- * Represent as unicode
- *
- * @param c
- * character to be encoded
- */
- protected void unicode(char c) {
- this.add("\\u");
- int n = c;
- for (int i = 0; i < 4; ++i) {
- int digit = (n & 0xf000) >> 12;
- this.add(hex[digit]);
- n <<= 4;
- }
- }
- public void setIgnoreHierarchy(boolean ignoreHierarchy) {
- this.ignoreHierarchy = ignoreHierarchy;
- }
- /**
- * If true, an Enum is serialized as a bean with a special property
- * _name=name() as all as all other properties defined within the enum.<br/>
- * If false, an Enum is serialized as a name=value pair (name=name())
- *
- * @param enumAsBean
- * true to serialize an enum as a bean instead of as a name=value
- * pair (default=false)
- */
- public void setEnumAsBean(boolean enumAsBean) {
- this.enumAsBean = enumAsBean;
- }
- protected static class JSONAnnotationFinder {
- private boolean serialize = true;
- private Method accessor;
- private String name;
- public JSONAnnotationFinder(Method accessor) {
- this.accessor = accessor;
- }
- public boolean shouldSerialize() {
- return serialize;
- }
- public String getName() {
- return name;
- }
- public JSONAnnotationFinder invoke() {
- JSON json = accessor.getAnnotation(JSON.class);
- serialize = json.serialize();
- if (serialize && json.name().length() > 0) {
- name = json.name();
- }
- return this;
- }
- }
- }
在你的工程中新建org.apache.struts2.json包,把以上代码复制到你的工程里就可以了,要注意的是,如果是在WEBLOGIC中部署,最好把这个类重新打包到struts2-json-plugin-2.3.15.3.jar包中,避免不必要的麻烦。
- 彻底解决SSH架构中的Hibernate懒加载问题
- 彻底解决SSH架构中的Hibernate懒加载问题
- 彻底解决hibernate懒加载转json
- 彻底解决SSH架构下的图片存取问题
- hibernate中的懒加载问题
- Hibernate中的懒加载问题
- Hibernate懒加载在SSH项目中的配置及原理
- java-web hibernate中的懒加载问题
- Hibernate中的懒加载
- 彻底解决J2ME中的中文问题
- wap中的乱码问题,彻底解决!
- 彻底解决J2ME中的中文问题
- 彻底解决J2ME中的中文问题
- 彻底解决J2ME中的中文问题
- 彻底解决J2ME中的中文问题
- 彻底解决J2ME中的中文问题
- hibernate懒加载问题
- hibernate懒加载问题
- Android控件之AutoCompleteTextView和MultiAutoCompleteTextView
- Android中的MVC设计模式
- 2016 Multi-University Training Contest 7题解报告
- 我从华为身上学到的项目管理经验 -- 编码阶段篇
- Mysql --分区表(5)Columns分区
- 彻底解决SSH架构中的Hibernate懒加载问题
- Qevent
- python学习(1)
- hdu 5805 简单思维题
- redis的主从复制配置
- 我从华为身上学到的项目管理经验 -- 测试篇
- UFLDL cnnInitParams.m cnnParamsToStack.m computeNumericalGradient.m
- HDU5818(多校第七场)——Joint Stacks(优先队列,左偏树)
- 8种常见算法比较