When using JPA/Hibernate, there are some common errors.

javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session

This means when Hibernate is trying to save entities when committing the transaction, two new entities have been added but they are related to the same database table row. You should check the Cascading settings of your entities. You may declare CascadeType.PERSIST or CascadeType.ALL on one of your entities, but still trying to persist dependent entities explictly using save. This will cause two entities to be persisted: One from cascading and another one from explict persisting operation. You can remove the explict persisting operation and let Hibernate to manage dependent entities.

Below is a simple example.

class User {  
  @OneToMany(cascade=CascadeType.ALL, mappedBy="user")
  private Set<Role> roles; 
}

user.addRole(role); //Role entity will be saved by cascading  
roleDao.save(role); //This causes javax.persistence.EntityExistsException  

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role

This is a very common issue when using Hibernate managed objects in web layer. If you google it, you can find hundreds of pages about this issue. Hibernate official document is a good start point to understand this issue.

When an entity object has a lazily-loaded collection and this object is passed to the web layer. When web layer code trying to access entity's collection object, objects in the collection need to be loaded. But the Hibernate session has already been closed, then Hibernate throws org.hibernate.LazyInitializationException. After understanding how this issue may happen, it's easy to find out how to solve it.

Load eagerly

Instead of loading collections lazily, you can load them eagerly. This means collections of this entity object have already been populated before used. To do this, use FetchType.EAGER.

class User {  
  @OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL, mappedBy="user")
  private Set<Role> roles; 
}

Loading eagerly may have performance issues because it may load unnecessary objects into memory. So check usage of the entity object first before applying this. In the above example, it's common that Role objects are also accessed when using User objects, so it makes sense to load Role entities eagerly.

Keep Hibernate session open

Another solution is to keep the Hibernate session open in web layer code, then when web layer code trying to load collection objects, the session is still open to do the loading. This is usually referred as Open Session In View pattern. This pattern has been widely used for a long time, Spring framework has support for this pattern. But this pattern is not considered as a good practice. It pollutes the web layer code with Hibernate exceptions and may have performance issues.

Load on-demand

If keeping Hibernate session open is not a good option and you want to fully populate an entity object, you can initialize it manually. Hibernate provides Hibernate.initialize method to initialize lazy-loading collections.

For the code below, User entity's roles collection is lazily loaded. Use Hibernate.initialize(user) to load roles collection.

class User {  
  @OneToMany(cascade=CascadeType.ALL, mappedBy="user")
  private Set<Role> roles; 
}

Sometimes an entity object has many lazy-loading collections and entities in those collections have other lazy-loading collections. To fully populate an object graph, you may need to use Hibernate.initialize multiple times. Below is a utility class to fully populate an object graph. Use HibernateUtils.recursiveInitialize to fully populate an object graph. com.myapp.model is the package name of model classes, which is used to avoid checking irrelevant classes.

import java.beans.PropertyDescriptor;  
import java.util.Collection;  
import java.util.HashSet;

import org.apache.commons.beanutils.PropertyUtils;  
import org.hibernate.Hibernate;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;

import com.google.common.collect.Sets;

public class HibernateUtils {  
  private HibernateUtils() {

  }

  private static final Logger logger = LoggerFactory
      .getLogger(HibernateUtils.class);

  public static void recursiveInitialize(Object obj) {
    new RecursiveInitializer().initialize(obj);
  }

  private static class RecursiveInitializer {
    private HashSet<Object> checkedObjects = Sets.newHashSet();

    public void initialize(Object obj) {
      if (obj == null || obj.getClass().getCanonicalName() == null) {
        return;
      }
      if (checkedObjects.contains(obj)
          || !obj.getClass().getCanonicalName()
              .contains("com.myapp.model")) {
        return;
      }
      checkedObjects.add(obj);
      if (!Hibernate.isInitialized(obj)) {
        Hibernate.initialize(obj);
      }
      PropertyDescriptor[] properties = PropertyUtils
          .getPropertyDescriptors(obj);
      for (PropertyDescriptor propertyDescriptor : properties) {
        try {
          Object propertyObj = PropertyUtils.getProperty(obj,
              propertyDescriptor.getName());
          if (propertyObj != null) {
            initialize(propertyObj);
          }
          if (propertyObj instanceof Collection<?>) {
            for (Object item : (Collection<?>) propertyObj) {
              initialize(item);
            }
          }
        } catch (Exception e) {
          logger.warn("Ignore property : " + propertyDescriptor, e);
        }
      }
    }
  }
}

Use DTO

Use DTO - Data transfer object is another solution. DTOs are simple objects with no relations to Hibernate managed entities. DTOs are easy to use in web layer.

Code below is an example of using DTOs. UserDto is the DTO object of User entity object. It doesn't have any Hibernate annotations and refer to another DTO class RoleDto.

class UserDto {  
  private Set<RoleDto> roles;
}