Frank Provost Frank Provost - 3 months ago 18
Java Question

SpringBootTest not resolving parent child relation - failed to lazy initialize

I'm using springBootTest to test a service I've created. In the before each function i create a parententity using the repository directly.

parentEntity = parentEntityRepository.saveAndFlush(ObjectMother.getParentEntityBuilder().string3("s3").build());


Within my test i create a childentity

childEntity = childEntityRepository.saveAndFlush(ObjectMother.getChildEntityBuilder().parentEntity(parentEntity).build());


The children relation is defined as follows

@Getter @Setter
@OneToMany(orphanRemoval = true)
@JoinColumn(name="PARENTENTITY_ID", updatable = false)
private Set<ChildEntity> children;


This is called within the test

parentEntity = parentEntityService.read(requestContext, parentEntity.getId());
parentEntity.getChildren().forEach(child -> Assert.assertNotNull(child.getText()));


It causes the following error

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sap.icn.pi.test.data.mcp.ParentEntity.children, could not initialize proxy - no Session


If i add @Transactional to my test method i receive the following

java.lang.NullPointerException // for parentEntity.getChildren()


** Edit: Code Snippets **

@Test
public void get_children_through_parent() {
parentEntity = parentEntityService.read(requestContext, 1);

parentEntity.getChildren().forEach(child -> Assert.assertNotNull(child));
parentEntity.getChildren().forEach(child -> Assert.assertNull(child.getTooltip()));
}


ParentEntity Class

@Entity
@Table(name = "T_PARENTENTITY")
@SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "SEQ_PARENTENTITY")
@Builder @NoArgsConstructor @AllArgsConstructor
@Localized
public class ParentEntity extends BaseEntity{

... //props

@Getter @Setter
@OneToMany(orphanRemoval = true)
@JoinColumn(name="PARENTENTITY_ID", updatable = false)
private Set<ChildEntity> children;
}

Answer

This is a common JPA/Hibernate problem. Object was read is different Hibernate session or hibernate session doesn't exist anymore, so lazy loading can't do SQL query to retrieve lazy dependency. Reason of this situation can vary and you didn't provide enough context.

To fix that, you have various options:

  1. Make sure that object is read and lazy dependency is loaded in same Hibernate session. Spring Automatically creates hibernate session per controller request, so it would be good to make sure that you object is not retrieved in servlet filter and lazy dependency in your controller/service. Or common problem is also passing that object into separate thread.
  2. Change dependency to be EAGER:

    @Getter @Setter
    @OneToMany(orphanRemoval = true, fetch = FetchType.EAGER)
    @JoinColumn(name="PARENTENTITY_ID", updatable = false)
    private Set<ChildEntity> children;