Search code examples
hibernatejpaspring-bootspring-transactionslazy-initialization

Hibernate jpa entity manager not being closed in spring service layer


I am developing a web service application using Spring Boot and Hibernate JPA. I have a layered architecture which consists of request controller layer, business logic (service) layer, and data access (repository) layer. The domain model/entity are:

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;
    @OneToMany
    @JoinColumn(name = "userId")
    private List<Address> addresses;
}

@Entity
public class Address {

    @Id
    @GeneratedValue
    private Long id;
}

As you can see, I have a User entity with one to many unidirectional relationship with address with lazy loading strategy. In repository layer, I have a simple user repository which extends spring data JpaRepository.

public interface UserRepository extends JpaRepository<User, Long> {
}

In service layer, simple user fetching method without business logic.

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public User getUser(Long id) {
        return this.userRepository.findOne(id);
    }
}

In controller simple user resource controller method.

@RestController
@RequestMapping(value = "/api/v1/users")
public class UserResource {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
    public User getUser(@PathVariable Long userId) {
        return this.userService.getUser(userId);
    }
}

My problem is when I try to get user from service layer, I will also get addresses of user though it is declared for lazy initialization. I also haven't enable transaction. I haven't called any getter method anywhere except when JSON serialization in controller. Hibernate JPA entity manager will still be open in controller layer. But I can't figure how. Wasn't I supposed to get lazy initialization exception?


Solution

  • Spring Boot registers an OpenEntityManagerInViewInterceptor (check the class JpaBaseConfiguration), which ensures that the entity manager is open for the complete request, which means, the lazy collection can be resolved while serializing the entity to JSON.

    If you want to disable that behaviour, add the configuration spring.jpa.open-in-view=false to your application.properties.