WEB开发网
开发学院软件开发Java Hibernate通用序列化方案,避免延迟加载问题及序列... 阅读

Hibernate通用序列化方案,避免延迟加载问题及序列化整个数据库至客户端

 2009-09-21 00:00:00 来源:WEB开发网   
核心提示:在使用Ajax: Hibernate Entity => json,Flex RemoteObject:Hibernate Entity => ActionScript Object的过程,经常碰到如下问题:问题:1.Hibernate碰到延迟加载的属性访问时如果session被关闭则抛出LazyIniti

在使用Ajax: Hibernate Entity => json, Flex RemoteObject: Hibernate Entity => ActionScript Object的过程,经常碰到如下问题:

问题:

1.Hibernate碰到延迟加载的属性访问时如果session被关闭则抛出LazyInitializationException

2.Hibernate中的one-to-many等关联关系在序列化时如果没有控制,则将整个数据库都有可能被全部序列化

3.过多的使用DTO/ValueObject解决这个问题.

解决办法:

对Entity对象生成一个动态代理,拦截getXXXX()方法,如果访问的是延迟加载的属性,则return null,而不抛出LazyInitializationException,递归生成属性的代码,只要碰到未延迟加载的属性,而序列化会自动停止.避免将整个Entity序列化传播,导致可能序列化整个数据库的问题.

类似解决方案:

dwr中HibernateConverter,在序列化时如上类似,碰到延迟加载的属性自动停止convert工作.而HibernateBeanSerializer则一劳永逸,无论object => json都可以工作.

使用用例:

Java代码   

//role为原始对象 
role = (Role)roleDao.getById(new Long(1)); 
//生成的动态代理proxyRole,访问延迟加载的属性将return null 
Role proxyRole = (Role)new HibernateBeanSerializer<Role>(role).getProxy(); 
assertNotNull(role.getResource());  
assertNull(proxyRole.getResource()); //延迟加载,为null 
 
Hibernate.initialize(role.getResource()); //抓取进来 
assertNotNull(proxyRole.getResource()); //不为null

源码.

Java代码   

package cn.org.rapid_framework.util; 
 
import java.lang.reflect.Modifier; 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.LinkedHashMap; 
import java.util.LinkedHashSet; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
 
import org.aopalliance.intercept.MethodInterceptor; 
import org.aopalliance.intercept.MethodInvocation; 
import org.hibernate.Hibernate; 
import org.hibernate.collection.PersistentCollection; 
import org.hibernate.proxy.HibernateProxy; 
import org.springframework.aop.framework.ProxyFactory; 
import org.springframework.util.StringUtils; 
 
/** 
 * 用于Hibernate Object 的序列化,访问延迟加载的属性不会抛出LazyInitializationException,而会返回null值. 
 * 使用: 
 * <pre> 
 * Blog proxyBlog = new HibernateBeanSerializer(blog).getProxy(); 
 * </pre> 
 * @author badqiu 
 * @param <T> 
 */ 
public class HibernateBeanSerializer <T> { 
 T proxy = null; 
 /** 
 */ 
 public HibernateBeanSerializer(T object,String... excludesProperties) { 
 if(object == null) { 
  this.proxy = null; 
 }else { 
  ProxyFactory pf = new ProxyFactory(); 
  pf.setTargetClass(object.getClass()); 
  pf.setOptimize(true); 
  pf.setTarget(object); 
  pf.setProxyTargetClass(true); 
  pf.setOpaque(true); 
  pf.setExposeProxy(true); 
  pf.setPreFiltered(true); 
  HibernateBeanSerializerAdvice beanSerializerAdvice = new HibernateBeanSerializerAdvice(); 
  beanSerializerAdvice.setExcludesProperties(excludesProperties); 
  pf.addAdvice(beanSerializerAdvice); 
  
  this.proxy = (T)pf.getProxy(); 
 } 
 } 
 
 public T getProxy(){ 
 return this.proxy; 
 } 
 
 static private class HibernateBeanSerializerAdvice implements MethodInterceptor { 
 private String[] excludesProperties = new String[0]; 
 public String[] getExcludesProperties() { 
  return excludesProperties; 
 } 
 public void setExcludesProperties(String[] excludesProperties) { 
  this.excludesProperties = excludesProperties == null ? new String[0] : excludesProperties; 
 } 
 public Object invoke(MethodInvocation mi) throws Throwable { 
  String propertyName = getPropertyName(mi.getMethod().getName()); 
  Class returnType = mi.getMethod().getReturnType(); 
  
  if(propertyName == null) { 
  return mi.proceed(); 
  } 
  if(!Hibernate.isPropertyInitialized(mi.getThis(), propertyName)) { 
  return null; 
  } 
  if(isExclude(mi, propertyName)) { 
  return null; 
  } 
  
  Object returnValue = mi.proceed(); 
  return processReturnValue(returnType, returnValue); 
 } 
  
 private Object processReturnValue(Class returnType, Object returnValue) { 
  if(returnValue == null) 
  return null; 
  if(returnType != null && Modifier.isFinal(returnType.getModifiers())) { 
  return returnValue; 
  } 
  //This might be a lazy-collection so we need to double check 
  if(!Hibernate.isInitialized(returnValue)) { 
  return null;   
  } 
  
  //this is Hibernate Object 
  if(returnValue instanceof HibernateProxy) { 
  return new HibernateBeanSerializer(returnValue).getProxy(); 
  }else if(returnValue instanceof PersistentCollection) { 
  if(returnType.isAssignableFrom(Map.class)) { 
   Map proxyMap = new LinkedHashMap(); 
   Map map = (Map)returnValue; 
   Set<Map.Entry> entrySet = map.entrySet(); 
   for(Map.Entry entry : entrySet) { 
   proxyMap.put(entry.getKey(), new HibernateBeanSerializer(entry.getValue())); 
   } 
   return proxyMap; 
  } 
   
  Collection proxyCollection = null; 
  if(returnType.isAssignableFrom(Set.class)) { 
   proxyCollection = new LinkedHashSet(); 
  }else if(returnType.isAssignableFrom(List.class)) { 
   proxyCollection = new ArrayList(); 
  }else { 
   return returnValue; 
  } 
   
  for(Object o : (Collection)returnValue) { 
   proxyCollection.add(new HibernateBeanSerializer(o).getProxy()); 
  } 
  return proxyCollection; 
  }else { 
  return returnValue; 
  } 
 } 
 
 private boolean isExclude(MethodInvocation mi, String propertyName) 
  throws Throwable { 
  
  for(String excludePropertyName : excludesProperties) { 
  if(propertyName.equals(excludePropertyName)) { 
   return true; 
  } 
  } 
  
  return false; 
 } 
  
 private static String getPropertyName(String methodName) { 
  String propertyName = null; 
  if(methodName.startsWith("get")) { 
  propertyName = methodName.substring("get".length()); 
  }else if(methodName.startsWith("is")) { 
  propertyName = methodName.substring("is".length()); 
  }else if(methodName.startsWith("set")) { 
  propertyName = methodName.substring("set".length()); 
  } 
  return propertyName == null ? null : StringUtils.uncapitalize(propertyName); 
 } 
 } 
} 

1 2  下一页

Tags:Hibernate 通用 序列化

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接