2

I'm migrating my Spring Boot REST API from 1.5.4 to 2.0.3.

These are my two entities, a repository for one of them and a controller for accessing them:

Parent.java

@Entity
@Table(name = "PARENT")
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    private List<Child> children;
}

Child.java

@Entity
@Table(name = "CHILD")
public class Child implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @Column(name = "PARENT_ID")
    private Long parentId;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;

    @Column(name = "name")
    private String name;
}

ParentRepository.java

public interface ParentRepository extends JpaRepository<Parent, Long> {

}

ParentController.java

@RestController
@RequestMapping("/parents")
public class ParentController {

    @Autowired
    private ParentRepository parentRepository;

    @RequestMapping(method = RequestMethod.GET)
    public List<Parent> getParents() {
        return parentRepository.findAll();
    }
}

It appears that there is no longer an active session in the @RestController classes since

parentRepository.findAll().get(0).getChildren().get(0).getName();

now throws a

LazyInitializationException: failed to lazily initialize a collection of role: com.mycompany.myapplication.entity.Parent.children, could not initialize proxy - no Session

This can be fixed by setting a @Transactional annotation on either the controller method or the controller class.


However, the problem I have regards the lazily loaded children.

If I run the example code above, even with the @Transactional annotation, I get the same exception but with a nested

com.fasterxml.jackson.databind.JsonMappingException

This is due to the serialization to JSON happens outside of the controller, hence outside the active session.

There is an ugly fix for this, by reading some data from each child before exiting the method:

@RequestMapping(method = RequestMethod.GET)
public List<Parent> getParents() {
    List<Parent> parents = parentRepository.findAll();
    parents.stream()
        .flatMap(p -> p.getChildren().stream())
        .forEach(Child::getName);
    return parents;
}

This works, but is terribly ugly and adds a lot of boilerplate.

Another solution would be to map all entities to DTOs before returning them to the client. But this solution adds another layer to my application which I don't want.


Is there a way to make sure that there is an active session during the automagical serialization of the entities?

darksmurf
  • 3,747
  • 6
  • 22
  • 38

1 Answers1

0

Soo yeaah...

During migration I had previously set

spring.jpa.open-in-view = false

because I saw a new warning about it in the log. This setting removes the active session I wanted help adding...

Removing this setting and using the default (true) fixed my problem entirely.

darksmurf
  • 3,747
  • 6
  • 22
  • 38