Closed sphsyv closed 9 years ago
@juqkai
这与JSON将对象转换成MAPL一样的。
你可以考虑使用 JsonField 注解
@juqkai 不能考虑JsonField注释,如果加了注释就永远都不会解析了, 我的hibernate查询有时候会预先抓取车辆信息里面的deviceType类的信息,这时候我是要解析这个属性的;有的查询页面就不需要这个信息,那么我就没有使用join fetch关键字,这个deviceType信息就没有查询,这个时候解析json就会出错。 根本解决问题的方式,就是在转换mapl的时候,直接传递需要忽略的属性,或者需要解析的属性,程序是不知道我什么时候需要什么属性,但是开发人员知道。所以某些方法需要转换这个属性,某些方法又不需要,不能写jsonField注释的,太死了。 我看了一下源码,有一句会将属性put到一个变量中,在这之前判断一下,是不是忽略属性,如果是就不放到变量中,这样就不会解析了估计。 还是不想直接修改源码,请大神增加一个方法吧??
@juqkai 教教我怎么动态JsonField呗,或者mapl在构造的时候怎样添加排除属性呢?
有个变通的方法,先转json, 因为toJson的时候可以通过JsonFormat忽略一些属性,然后再转回对象
我自己写了个类解决了。 类内容如下:
package sy.util.base;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.nutz.json.Json;
import org.nutz.lang.Mirror;
import org.springframework.beans.BeanUtils;
/**
* 为了解决hibernate懒加载序列化json出错,再次封装一层
*
* @author 孙宇
*
*/
public class JsonUtil {
/**
* 对象转json字符串
*
* @param obj
* @param excludePath
* 要排除的属性路由(要符合Mapl的path规则)
* @return
*/
public static String toJsonByExclude(Object obj, String[] excludePath) {
return Json.toJson(excludeAttributes(obj, excludePath));
}
/**
* 排除不需要的属性
*
* @param obj
* 原对象
* @param excludePath
* 不需要的属性路径
* @return
*/
public static Object excludeAttributes(Object obj, String[] excludePath) {
Object o = null;
if (obj instanceof Collection) {
List<Object> oList = new ArrayList<Object>();
for (Object t : (List<Object>) obj) {
Object nt = Mirror.me(t).born();
BeanUtils.copyProperties(t, nt);
oList.add(nt);
}
o = oList;
} else {
try {
o = obj.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
BeanUtils.copyProperties(obj, o);
}
for (String path : excludePath) {
setAttributeNull(o, path);
}
return o;
}
private static void setAttributeNull(Object o, String path) {
Mirror<?> mirror = Mirror.me(o);
excludeHibernateProxy(o, mirror);
if (path.indexOf(".") > 0) {
String[] paths = path.split("\\.");
String newPath = "";
for (int i = 1; i < paths.length; i++) {
if (i > 1) {
newPath += ".";
}
newPath += paths[i];
}
if (paths[0].indexOf("[") > -1) {// 第一个需要过滤的路由是集合属性
Collection<?> collection;
if (paths[0].indexOf("[") == 0) {// [].attribute
collection = (Collection<?>) o;
} else {// attribute[].attribute
collection = (Collection<?>) mirror.getValue(o, paths[0].substring(0, paths[0].indexOf("[")));
}
if (collection != null && collection.size() > 0) {
Iterator<?> iterator = collection.iterator();
while (iterator != null && iterator.hasNext()) {
setAttributeNull(iterator.next(), newPath);
}
}
} else {// attribute.attribute
setAttributeNull(mirror.getValue(o, paths[0]), newPath);
}
} else {// attribute
mirror.setValue(o, path, null);
}
}
private static void excludeHibernateProxy(Object o, Mirror<?> mirror) {
for (Field field : mirror.getFields()) {
Object value = mirror.getValue(o, field);
if (value instanceof HibernateProxy) {// hibernate代理对象
LazyInitializer initializer = ((HibernateProxy) value).getHibernateLazyInitializer();
if (initializer.isUninitialized()) {
mirror.setValue(o, field, null);
}
} else if (value instanceof PersistentCollection) {// 实体关联集合
PersistentCollection collection = (PersistentCollection) value;
if (!collection.wasInitialized()) {
mirror.setValue(o, field, null);
} else if (collection.getValue() == null) {
mirror.setValue(o, field, null);
}
}
}
}
}
调用方式:
IovBizCarInfo car = service.get(filter);
JsonResult j = new JsonResult();
j.setObj(JsonUtil.excludeAttributes(car, new String[] { "iovBizDevices[].iovBizCarInfo" }));
j.setSuccess(true);
return j;
这样就排除了car对象里的iovBizDevices集合里的iovBizCarinfo属性,避免了循环引用的问题。
赞
在我的项目中使用了hibernate。目前发现的问题是: 在action中,代码如下 List l = service.find(filter);//查询所有车辆对象(车辆对象里面有设备类型对象)
Object j = Mapl.toMaplist(l);//转成mapl格式
Object json = Mapl.excludeFilter(j, Arrays.asList("deviceType"));//过滤设备类型,不进行json解析
现在的情况是,第2句话,转成mapl格式就出错了,下面的过滤根本就没走到 错误描述: java.lang.RuntimeException: Fail to invoke getter org.hibernate.proxy.AbstractLazyInitializer.'isReadOnly()' because [org.hibernate.TransientObjectException: Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session.]: Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session. at org.nutz.lang.Lang.makeThrow(Lang.java:99) at org.nutz.lang.eject.EjectByGetter.eject(EjectByGetter.java:26) at org.nutz.json.entity.JsonEntityField.getValue(JsonEntityField.java:141) at org.nutz.mapl.impl.compile.ObjCompileImpl.pojo2Json(ObjCompileImpl.java:123) at org.nutz.mapl.impl.compile.ObjCompileImpl.parse(ObjCompileImpl.java:82) at org.nutz.mapl.impl.compile.ObjCompileImpl.pojo2Json(ObjCompileImpl.java:128) at org.nutz.mapl.impl.compile.ObjCompileImpl.parse(ObjCompileImpl.java:82) at org.nutz.mapl.impl.compile.ObjCompileImpl.pojo2Json(ObjCompileImpl.java:128) at org.nutz.mapl.impl.compile.ObjCompileImpl.parse(ObjCompileImpl.java:82) at org.nutz.mapl.impl.compile.ObjCompileImpl.pojo2Json(ObjCompileImpl.java:128) at org.nutz.mapl.impl.compile.ObjCompileImpl.parse(ObjCompileImpl.java:82) at org.nutz.mapl.impl.compile.ObjCompileImpl.coll2Json(ObjCompileImpl.java:157) at org.nutz.mapl.impl.compile.ObjCompileImpl.parse(ObjCompileImpl.java:70) at org.nutz.mapl.Mapl.toMaplist(Mapl.java:141) at com.autolink.controller.business.IovBizCarInfoController.findJoinRtLocation(IovBizCarInfoController.java:163)
我的建议是:在转换mapl格式的时候,就将要排除的属性,或者要解析的属性已参数的方式传递进去,避免hibernate懒加载出错。 例如 Object j = Mapl.toMaplist(l,includeFilter); Object j = Mapl.toMaplist(l,excludeFilter); 就相当于将 Object j = Mapl.toMaplist(l); Object json = Mapl.excludeFilter(j, Arrays.asList("deviceType")); 合并成 Object j = Mapl.toMaplistByExcludeFilter(l,Arrays.asList("deviceType")); 在转换mapl的时候,就告诉mapl要过滤那些属性,或者包含那些属性,避免出错??