'Get org.hibernate.LazyInitializationException in spring boot integration test

I'm trying to write integration test for Spring Boot application. I have Product and GalleryImage domain model. They are in one-to-many relationship.

public class Product {
    ...

    @OneToMany(mappedBy = "product")
    private List<GalleryImage> galleryImages;
}

I have a integration test as below:

@Test
public void testProductAndGalleryImageRelationShip() throws Exception {
    Product product = productRepository.findOne(1L);
    List<GalleryImage> galleryImages = product.getGalleryImages();
    assertEquals(1, galleryImages.size());
}

However, this test gives me a LazyInitializationException. I searched on Google and StackOverFlow, it says that the session is closed after productRepository.findOne(1L), since galleryImages are lazily loaded, so galleryImages.size() gives me this exception.

I have tried to add a @Transactional annotation on the test, but it's still not working.



Solution 1:[1]

Hibernate Session has been closed after following line productRepository.findOne(1L).

You can try to do Hibernate.initialize(product.getGalleryImages())

public static void initialize(Object proxy)
                   throws HibernateException

Force initialization of a proxy or persistent collection. Note: This only ensures intialization of a proxy object or collection; it is not guaranteed that the elements INSIDE the collection will be initialized/materialized.

To avoid Hibernate.initialize you can create a service.

@Service
@Transactional
public class ProductService {

    @Transactional(readOnly = true)
    public List<GalleryImage> getImages(final long producId) throws Exception {
      Product product = productRepository.findOne(producId);
      return product.getGalleryImages();
  }
}

If you do use Spring Data JPA in you application then dynamic finder is a good alternative.

Solution 2:[2]

I had similar issues in the past and the solution was indeed adding the @Transactional annotation, but contrarily to what is proposed by @Anton M answer I believe that in this case we should annotate the test instead as proposed here.

It works both ways but the annotation should be placed if and where necessary, i.e. add it on the service if you need it there and not just for testing purposes.

For example, keep this as it was:

public class Product {
    ...

    @OneToMany(mappedBy = "product")
    private List<GalleryImage> galleryImages;
}

And add the annotation here:

@Test
@Transactional
public void testProductAndGalleryImageRelationShip() throws Exception {
    Product product = productRepository.findOne(1L);
    List<GalleryImage> galleryImages = product.getGalleryImages();
    assertEquals(1, galleryImages.size());
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Anton N
Solution 2 João Matos