Hibernate: how to get a list of all the objects currently in the session
Asked Answered
L

3

18

I'm getting the good, old and dreaded TransientObjectException, and, as often happens in such case, I'm having problems locating what kind of subtle bug in the code is causing the problem.

My question is: is there a way to obtain a list of every object that's in the current Hibernate session?

I'll probably have solved the current problem by the time I get an answer for this question, but, anyway, being able to list everything that is the session would help a lot in the next time that happens.

Liquidate answered 9/5, 2013 at 11:33 Comment(0)
W
20

Hibernate does not expose its internals to the public, so you won't find what you are searching for in the public API. However you can find your answer in the implementation classes of the Hibernate interfaces: This method (taken from http://code.google.com/p/bo2/source/browse/trunk/Bo2ImplHibernate/main/gr/interamerican/bo2/impl/open/hibernate/HibernateBo2Utils.java) will tell if an object exists in the session:

public static Object getFromSession
        (Serializable identifier, Class<?> clazz, Session s) {              
    String entityName = clazz.getName();
    if(identifier == null) {
       return null;
    }      
    SessionImplementor sessionImpl = (SessionImplementor) s;
    EntityPersister entityPersister = sessionImpl.getFactory().getEntityPersister(entityName);
    PersistenceContext persistenceContext = sessionImpl.getPersistenceContext();
    EntityKey entityKey = new EntityKey(identifier, entityPersister, EntityMode.POJO);
    Object entity = persistenceContext.getEntity(entityKey);
    return entity;
    }

If you drill down a little more, you will see that the only implementation of PersistenceContext is org.hibernate.engine.StatefulPersistenceContext. This class has the following collections:

// Loaded entity instances, by EntityKey
private Map entitiesByKey;

// Loaded entity instances, by EntityUniqueKey
private Map entitiesByUniqueKey;

// Identity map of EntityEntry instances, by the entity instance
private Map entityEntries;

// Entity proxies, by EntityKey
private Map proxiesByKey;

// Snapshots of current database state for entities
// that have *not* been loaded
private Map entitySnapshotsByKey;

// Identity map of array holder ArrayHolder instances, by the array instance
private Map arrayHolders;

// Identity map of CollectionEntry instances, by the collection wrapper
private Map collectionEntries;

// Collection wrappers, by the CollectionKey
private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection

// Set of EntityKeys of deleted objects
private HashSet nullifiableEntityKeys;

// properties that we have tried to load, and not found in the database
private HashSet nullAssociations;

// A list of collection wrappers that were instantiating during result set
// processing, that we will need to initialize at the end of the query
private List nonlazyCollections;

// A container for collections we load up when the owning entity is not
// yet loaded ... for now, this is purely transient!
private Map unownedCollections;

// Parent entities cache by their child for cascading
// May be empty or not contains all relation 
private Map parentsByChild;

So, what you need to do is cast the PersistenceContext to a StatefulPersistenceContext, then use reflection to get the private collection that you want and then iterate on it.

I strongly suggest you do that only on debugging code. This is not public API and it could brake by newer releases of Hibernate.

Wager answered 9/5, 2013 at 12:26 Comment(1)
Thanks; that will help a lot the next time the problem happens. ;)Liquidate
T
14

Found @nakosspy post very useful. Inspired by his post, I added this very simple utility method that outputs the contents of Hibernate Session.

As nakosspy said this is ONLY for debugging purposes as it is a HACK.

    public static void dumpHibernateSession(Session s) {
    try {
        SessionImplementor sessionImpl = (SessionImplementor) s;
        PersistenceContext persistenceContext = sessionImpl.getPersistenceContext();
        Field entityEntriesField = StatefulPersistenceContext.class.getDeclaredField("entityEntries");
        entityEntriesField.setAccessible(true);
        IdentityMap map = (IdentityMap) entityEntriesField.get(persistenceContext);
        log.info(map);
    } catch (Exception e)
    {
        log.error(e);
    }

}
Twill answered 4/7, 2014 at 8:54 Comment(1)
For hibernate 4.3.11 you need to use StatefulPersistenceContext.class.getDeclaredField("entitiesByKey"); and store it as a Map (or some other field, since entityEntries does not exist) -- but aside from that the concept is solid.Pelvic
A
1

Updating the answer of @Gaetano you can add to any Spring JPA component:

@Autowired
EntityManager entityManager;

public void dumpHibernateSession() {
    try {
        SessionImplementor sessionImpl = entityManager.unwrap(SessionImplementor.class);
        PersistenceContext persistenceContext = sessionImpl.getPersistenceContext();
        Field entityEntriesField = StatefulPersistenceContext.class.getDeclaredField("entitiesByKey");
        entityEntriesField.setAccessible(true);
        Object map = entityEntriesField.get(persistenceContext);
        System.out.println(String.format("!!!dump hibernate: %s", map));
    } catch (Exception e) {
        System.out.println(e);
    }
}
Adrianaadriane answered 2/2 at 8:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.