Hibernate: best practice to pull all lazy collections Hibernate: best practice to pull all lazy collections java java

Hibernate: best practice to pull all lazy collections


Use Hibernate.initialize() within @Transactional to initialize lazy objects.

 start Transaction       Hibernate.initialize(entity.getAddresses());      Hibernate.initialize(entity.getPersons()); end Transaction 

Now out side of the Transaction you are able to get lazy objects.

entity.getAddresses().size();entity.getPersons().size();


You can traverse over the Getters of the Hibernate object in the same transaction to assure all lazy child objects are fetched eagerly with the following generic helper class:

HibernateUtil.initializeObject(myObject, "my.app.model");

package my.app.util;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashSet;import java.util.Set;import org.aspectj.org.eclipse.jdt.core.dom.Modifier;import org.hibernate.Hibernate;public class HibernateUtil {public static byte[] hibernateCollectionPackage = "org.hibernate.collection".getBytes();public static void initializeObject( Object o, String insidePackageName ) {    Set<Object> seenObjects = new HashSet<Object>();    initializeObject( o, seenObjects, insidePackageName.getBytes() );    seenObjects = null;}private static void initializeObject( Object o, Set<Object> seenObjects, byte[] insidePackageName ) {    seenObjects.add( o );    Method[] methods = o.getClass().getMethods();    for ( Method method : methods ) {        String methodName = method.getName();        // check Getters exclusively        if ( methodName.length() < 3 || !"get".equals( methodName.substring( 0, 3 ) ) )            continue;        // Getters without parameters        if ( method.getParameterTypes().length > 0 )            continue;        int modifiers = method.getModifiers();        // Getters that are public        if ( !Modifier.isPublic( modifiers ) )            continue;        // but not static        if ( Modifier.isStatic( modifiers ) )            continue;        try {            // Check result of the Getter            Object r = method.invoke( o );            if ( r == null )                continue;            // prevent cycles            if ( seenObjects.contains( r ) )                continue;            // ignore simple types, arrays und anonymous classes            if ( !isIgnoredType( r.getClass() ) && !r.getClass().isPrimitive() && !r.getClass().isArray() && !r.getClass().isAnonymousClass() ) {                // ignore classes out of the given package and out of the hibernate collection                // package                if ( !isClassInPackage( r.getClass(), insidePackageName ) && !isClassInPackage( r.getClass(), hibernateCollectionPackage ) ) {                    continue;                }                // initialize child object                Hibernate.initialize( r );                // traverse over the child object                initializeObject( r, seenObjects, insidePackageName );            }        } catch ( InvocationTargetException e ) {            e.printStackTrace();            return;        } catch ( IllegalArgumentException e ) {            e.printStackTrace();            return;        } catch ( IllegalAccessException e ) {            e.printStackTrace();            return;        }    }}private static final Set<Class<?>> IGNORED_TYPES = getIgnoredTypes();private static boolean isIgnoredType( Class<?> clazz ) {    return IGNORED_TYPES.contains( clazz );}private static Set<Class<?>> getIgnoredTypes() {    Set<Class<?>> ret = new HashSet<Class<?>>();    ret.add( Boolean.class );    ret.add( Character.class );    ret.add( Byte.class );    ret.add( Short.class );    ret.add( Integer.class );    ret.add( Long.class );    ret.add( Float.class );    ret.add( Double.class );    ret.add( Void.class );    ret.add( String.class );    ret.add( Class.class );    ret.add( Package.class );    return ret;}private static Boolean isClassInPackage( Class<?> clazz, byte[] insidePackageName ) {    Package p = clazz.getPackage();    if ( p == null )        return null;    byte[] packageName = p.getName().getBytes();    int lenP = packageName.length;    int lenI = insidePackageName.length;    if ( lenP < lenI )        return false;    for ( int i = 0; i < lenI; i++ ) {        if ( packageName[i] != insidePackageName[i] )            return false;    }    return true;}}


Not the best solution, but here is what I got:

1) Annotate getter you want to initialize with this annotation:

@Retention(RetentionPolicy.RUNTIME)public @interface Lazy {}

2) Use this method (can be put in a generic class, or you can change T with Object class) on a object after you read it from database:

    public <T> void forceLoadLazyCollections(T entity) {    Session session = getSession().openSession();    Transaction tx = null;    try {        tx = session.beginTransaction();        session.refresh(entity);        if (entity == null) {            throw new RuntimeException("Entity is null!");        }        for (Method m : entityClass.getMethods()) {            Lazy annotation = m.getAnnotation(Lazy.class);            if (annotation != null) {                m.setAccessible(true);                logger.debug(" method.invoke(obj, arg1, arg2,...); {} field", m.getName());                try {                    Hibernate.initialize(m.invoke(entity));                }                catch (Exception e) {                    logger.warn("initialization exception", e);                }            }        }    }    finally {        session.close();    }}