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.

2
  • The transaction is closed. If one knows one needs the related object, the relations should be fetched eagerly instead of lazily. Commented Jan 11, 2020 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) ... advanced issue here Commented Jan 11, 2020 at 13:38

2 Answers 2

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!

Sign up to request clarification or add additional context in comments.

7 Comments

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.
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?
@Turing85 Can you explain the meaning of business entities to me?
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
Yes, I've added the whole annotation
|
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 .

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.