10

I have this error:

2020-11-16 22:36:09.313 ERROR 19428 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: collection was evicted; nested exception is org.hibernate.HibernateException: collection was evicted] with root cause

org.hibernate.HibernateException: collection was evicted
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:43) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]

I create an API REST application, my entities have this composition:

public class Label {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long Id;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "label")
    private Set<Release> releases;
public class Release {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    
    @ManyToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "label_id")
    private Label label;
    

After the third API-REST request for create a release/label association data i have the error at the top

RestController:

    @PostMapping(value = "/release", consumes = "application/json", produces = "application/json")
    Release newRelease(@RequestBody ReleaseDto releaseDto) {
        return releaseService.addRelease(releaseDto);
    }

ReleaseService:

@Service("ReleaseService")
public class ReleaseServiceImpl implements ReleaseService{

    @Autowired
    ReleaseRepository repository;
    @Autowired
    LabelRepository labelRepository;
    
    @Override
    public Release addRelease(ReleaseDto releaseDto) {
        Release release = new Release();
        Optional<Label> label = labelRepository.findById(releaseDto.getLabel_id());
        if(label.isPresent()){
            release.setName(releaseDto.getName());
            release.setLabel(label.get());
            repository.save(release);
        }
        return release;
    }

I'm confused maybe i must implement an entity manager ?

Greetings.

DMine
  • 203
  • 2
  • 4
  • 13
  • 1
    Could you also add your addRelease method? It looks quite ok so far. – Thomas Nov 17 '20 at 16:35
  • @Thomas i used [lombok](https://projectlombok.org/) and in releaseDto i had `@Data notation` – DMine Nov 17 '20 at 16:39
  • 1
    I mean the service, implementing addRelease. Maybe you also have some unusual settings configuring hibernate? – Thomas Nov 17 '20 at 16:44
  • @Thomas i'm Junior in Spring, in my application i had this in my application.properties `spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.hibernate.ddl-auto=update§ spring.datasource.url=jdbc:mysql://IPXX:3306/DB spring.datasource.username=(Username) spring.datasource.password=(Password)` – DMine Nov 17 '20 at 16:49
  • @Thomas i did update on the top the piece of service. – DMine Nov 17 '20 at 16:57

2 Answers2

14
@EqualsAndHashCode.Exclude
@ToString.Exclude

I have added these two annotations for @onetomany object and my error got vanished. But I don't know how.

Raghunath
  • 141
  • 1
  • 5
  • 3
    Are you using Lombok's @Data annotation? That annocation creates equals and hashcode implementations that include checking the content of the OneToMany collections. This interferes with Hibernate's loading strategy, or something like that. Adding those annotations will prevent that the OneToMany collections get accessed too early. – Christoph Sep 15 '21 at 13:08
  • Do read this https://stackoverflow.com/a/65176911/3214988 – sunitkatkar Nov 11 '21 at 07:22
  • I have same problem and my problem was occurring in spring security, before added this annotation it worked. – salam_verdim_alana_panyatkasi Mar 27 '22 at 13:33
  • @Christoph 's answer indeed is correct. I faced the exact same issue and it got fixed by removing `@Data` and adding Getters/Setters annotations – Dorin Brage Mar 22 '23 at 09:52
2

As a first proposal, I would recommend to change this line:

release = repository.save(release)

The save method returns an updated object of the entity, so by returning the "non-updated" one, there may be problems when trying to serialize the response.

Following our discussion, probably removing CascadeType.ALL was the issue here - Hibernate tried to do some magic with the related entities, which were out of sync.

Maybe you also want to create a DTO for the Response, as it's good practice to separate this from the entity.

Using FetchType.EAGER is generally also not a good idea - some notes on this https://vladmihalcea.com/eager-fetching-is-a-code-smell/ . If you change this, you probably need to fetch the related entities manually in the service - changing to a separate DTO and this isn't an issue anyway.

You may check out https://bootify.io, you can create an example REST API (but not with your custom endpoint anyway).

Thomas
  • 451
  • 2
  • 5
  • Yo! I tried, to change these line, but doesn't work :( I saved your project and i will study it. I doesn't understand where i be wrong – DMine Nov 17 '20 at 17:12
  • 1
    Mhm not really sure either - you can remove the response from the service/controller for now, and see if the error is still there. – Thomas Nov 17 '20 at 17:18
  • I remove the response of controller, the error persist. – DMine Nov 17 '20 at 17:42
  • 1
    Another idea: try to remove the CascadeType.ALL - maybe Hibernate internally tries to update the Label with the set of Releases being outdated. – Thomas Nov 17 '20 at 19:48
  • 1
    I remove CascadeType.ALL, and i change all EAGER with LAZY, and it works ! Thank Thomas! Now read more scrupulously https://vladmihalcea.com/eager-fetching-is-a-code-smell/ and after this i wanna read your project https://bootify.io. Thank You ! – DMine Nov 17 '20 at 21:38