/**
* Copyright 2009 Roland Foerther, Carl-Eric-Menzel, Olaf Siefart
*
* Licensed 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 com.senacor.core.hibernate;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
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.collection.AbstractPersistentCollection;
import org.hibernate.collection.PersistentCollection;
import com.senacor.core.bo.BusinessObject;
/**
* Entfernt alle Hibernate Lazy Loading Maps und Collections aus dem
* Rückgabeobjekt
*
* @author osiefart
*/
public class RemoveHibernateLazyLoadingProxiesInterceptor implements MethodInterceptor {
@SuppressWarnings("unchecked")
public Object invoke(MethodInvocation invocation) throws Throwable {
Object returnObject = invocation.proceed();
if (isBusinessObject(returnObject)) {
removeHibernateProxy((BusinessObject) returnObject);
} else if (isCollection(returnObject)) {
removeHibernateProxy((Collection) returnObject);
}
return returnObject;
}
/**
* True, wenn das übergebene Objekt vom Typ BusinessObject ist
*
* @param object
* @return
*/
private boolean isBusinessObject(Object object) {
return (object instanceof BusinessObject);
}
/**
* True, wenn das übergebene Objekt vom Typ Collection ist
*
* @param object
* @return
*/
private boolean isCollection(Object object) {
return (object instanceof Collection);
}
/**
* True, wenn der Typ des Fields eine Collection ist
*
* @param field
* @return
*/
private boolean isCollection(Field field) {
return (Collection.class.isAssignableFrom(field.getType()));
}
/**
* True, wenn die Instanz om Objekt vom Typ PersistentCollection ist
*
* @param field
* @param businessObject
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private boolean isPersistentCollection(Field field, BusinessObject businessObject) throws IllegalArgumentException, IllegalAccessException {
Object object = field.get(businessObject);
return (object instanceof PersistentCollection);
}
/**
* True, wenn der Typ des Fields eine List ist
*
* @param field
* @return
*/
private boolean isList(Field field) {
return List.class.isAssignableFrom(field.getType());
}
/**
* True, wenn der Typ des Fields eine Map ist
*
* @param field
* @return
*/
private boolean isMap(Field field) {
return Map.class.isAssignableFrom(field.getType());
}
/**
* True, wenn der Typ des Fields ein Set ist
*
* @param field
* @return
*/
private boolean isSet(Field field) {
return Set.class.isAssignableFrom(field.getType());
}
/**
* Iteriert über die Collection und ersetzt in allen Objekten
* Lazy-Collections / Maps durch richtige Collection / Maps
*
* @param collection
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private void removeHibernateProxy(Collection collection) throws IllegalAccessException {
for (Object object : collection) {
if (isBusinessObject(object)) {
removeHibernateProxy((BusinessObject) object);
}
}
}
/**
* Iteriert durch alle Attribute des Objekts (unter aller Unterobjekte) und
* ersetzt Lazy-Collections / Maps durch richtige Collection / Maps
*
* @param businessObject
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private void removeHibernateProxy(BusinessObject businessObject) throws IllegalAccessException {
Field[] fields = getFields(businessObject.getClass());
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
field.setAccessible(true);
if (isPersistentCollection(field, businessObject)) {
if (isMap(field)) {
convertMap(field, businessObject);
} else if (isCollection(field)) {
convertCollection(field, businessObject);
}
convertCollection(field, businessObject);
removeHibernateProxy((Collection) field.get(businessObject));
}
}
}
/**
* Liefert alle Attribute der Klasse samt Oberklassen
*
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
private Field[] getFields(Class clazz) {
Field[] fields = new Field[] {};
fields = clazz.getDeclaredFields();
if (!clazz.getSuperclass().equals(BusinessObject.class)) {
Field[] addFields = getFields(clazz.getSuperclass());
Field[] tmp = new Field[fields.length + addFields.length];
System.arraycopy(fields, 0, tmp, 0, fields.length);
System.arraycopy(addFields, 0, tmp, fields.length, addFields.length);
fields = tmp;
}
return fields;
}
/**
* Erzeugt eine neuen Collection und überträgt alle Objekte in sie, wenn die
* vorherige LazyCollection initialisiert war
*
* @param field
* @param object
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private void convertCollection(Field field, Object object) throws IllegalAccessException {
Collection collection = (Collection) field.get(object);
Collection newCollection = createCollection(field);
newCollection.addAll(collection);
field.set(object, newCollection);
}
/**
* Erzeugt eine neuen Map und überträgt alle Objekte in sie, wenn die
* vorherige LazyMap initialisiert war
*
* @param field
* @param object
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private void convertMap(Field field, Object object) throws IllegalAccessException {
Map map = (Map) field.get(object);
Map newMap = createMap(field);
if (((AbstractPersistentCollection) object).wasInitialized()) {
newMap.putAll(map);
}
field.set(object, newMap);
}
/**
* Wenn der Typ des Fields eine List ist, wird eine Arraylist zurückgegeben.
*
* Wenn der Typ des Fields ein Set ist, wird ein HashSet zurückgegeben.
*
* Ansonsten null.
*
* @param field
* @return
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private Collection createCollection(Field field) throws IllegalAccessException {
if (isList(field)) {
return new ArrayList();
} else if (isSet(field)) {
return new HashSet();
}
return null;
}
/**
* Wenn der Typ des Fields eine Map ist, wird eine HashMap zurückgegeben,
* ansonsten null.
*
* @param field
* @return
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
private Map createMap(Field field) throws IllegalAccessException {
if (isMap(field)) {
return new HashMap();
}
return null;
}
}