0

I try to create a simple relationship between two entities with spring. There is one User entity that holds many profile entities.

User Entity

@Entity
public class User {

    @OneToMany(mappedBy = "user")
    private List<Profile> profiles;

    public List<Profile> getProfiles() {
        return profiles;
    }

    public void setProfiles(List<Profile> profiles) {
        this.profiles = profiles;
    }
}

Profile Entity

@Entity
public class Profile {

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

When I try to find a profile with this.profileRepository.findById(id).get() inside a @RestController I get this error:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: User.profiles, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: User.profiles, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->User["profiles"])]
The server encountered an unexpected condition that prevented it from fulfilling the request.

Can anyone explain to me why this is not working? I followed this tutorial.

Mandar Dharurkar
  • 267
  • 1
  • 5
  • 16
Markus
  • 1,909
  • 4
  • 26
  • 54
  • The transaction is closed. If one knows one needs the related object, the relations should be fetched eagerly instead of lazily. – Turing85 Jan 11 '20 at 12:56
  • There are no "rest controllers" in this tutorial (except the repositories... which have "built in" controllers), probably you are just missing a `@Transactional` annotation on your controller class/method ([like here](https://stackoverflow.com/q/49894587/592355)) ... [advanced issue here](https://stackoverflow.com/q/36583185/592355) – xerx593 Jan 11 '20 at 13:38

2 Answers2

2

as Mandar said, you can resolve it by eager fetch. But if you don't want to fetch all I mean eager fetch, then you have to initialize them for lazy fetch like this to the related class, your Profile class:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Entity
public class Profile implements Serializable{
//
//
.. your other stuffs
}

Edit: also change your User entity like this:

@Entity
public class User implements Serializable{

    @OneToMany(mappedBy = "user")
    private List<Profile> profiles = new LinkedHashSet<Profile>();
//...other stufs..
.
.
}

Hope, this will help!

user404
  • 1,934
  • 1
  • 16
  • 32
  • As an aside: I would generally advice to separate the business entities from the persistence entities, as well as the DTOs. So really, this one class should be three classes: a DTO for (external) representation, a business entity and a persistence entity. – Turing85 Jan 11 '20 at 13:19
  • Thanks for answering my question. As you described I've added the `@JsonIgnoreProperties` to the profile entity. But It's still the same problem. Can you explain it a little bit more? – Markus Jan 11 '20 at 13:21
  • @Turing85 Can you explain the meaning of business entities to me? – Markus Jan 11 '20 at 13:23
  • did you add this whole thing `@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})` ? Ok, this initialize for lazily fetched data in their deserialization process as those data does not fetched the first time you call for that object. Also, check my edit please – user404 Jan 11 '20 at 13:24
  • Yes, I've added the whole annotation – Markus Jan 11 '20 at 13:26
  • please check the updates.. I have implemneted Serializtion for both entities and initiazlied hashSet for oneToMany relation – user404 Jan 11 '20 at 13:29
  • @Markus that is out-of-scope for this question. In essence, it represents business data that is independent from the persistence- and representation-(web-)layer – Turing85 Jan 11 '20 at 13:29
1

I faced the same issue. But I was getting the error of " Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialise a collection of role:" because I did not have declared toString method in the viewDTO

Below are the things which I had done

  1. declared @Transactional in service method.
  2. declared the field in persistence DTO as below

 @Convert(converter = StringListConverter.class)
    @JsonIgnore
    @ElementCollection
    protected List<String> someField;
 

where

public class StringListConverter implements AttributeConverter<List<String>, String> {

    @Override
    public String convertToDatabaseColumn(List<String> list) {
        return String.join(",", list);
    }

    @Override
    public List<String> convertToEntityAttribute(String joined) {
        return new ArrayList<>(Arrays.asList(joined.split(",")));
    }

}
  1. was creating the viewDTO out of persistence DTO and setting the viewDTO in response entity .
Rama Sharma
  • 96
  • 11