Immutable list causes exception in save()

Let’s say you have an entity with a property of type List and you’re in the middle of your own save() mehtod in your service layer. You’re provided by DTO that came from admin frontend and preparing an entity to persist to the repository.

Original code:

final List<Article> relatedArticles =
	dto.getRelatedArticlesSorted().stream()
		.map( id -> this.articleRepository.findById( id ).orElse( null ) )
		.filter( Objects::nonNull )

		.collect( Collectors.toList() ); // NOSONAR 

entity.setRelatedArticles( relatedArticles );

Code that Sonar Lint proposes:

final List<Article> relatedArticles =
	dto.getRelatedArticlesSorted().stream()
		.map( id -> this.articleRepository.findById( id ).orElse( null ) )
		.filter( Objects::nonNull )

		.toList(); // generated list is immutable

entity.setRelatedArticles( relatedArticles );

The code which persists is simple:

this.articleRepository.save( entity );

While original code works perfectly, code proposed by SonarLint causes exception:

[ERROR] (CustomResponseEntityExceptionHandler.java:122) CustomResponseEntityExceptionHandler Exception: UnsupportedOperationException -> null
java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.clear(ImmutableCollections.java:149)
	at org.hibernate.collection.spi.PersistentList.clear(PersistentList.java:294)
	at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:506)
	at org.hibernate.type.CollectionType.replace(CollectionType.java:719)
	at org.hibernate.type.TypeHelper.replace(TypeHelper.java:117)
	at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:596)
	at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:286)
	at org.hibernate.event.internal.DefaultMergeEventListener.merge(DefaultMergeEventListener.java:220)
	at org.hibernate.event.internal.DefaultMergeEventListener.doMerge(DefaultMergeEventListener.java:152)
	at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:136)
	at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:89)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
	at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:854)
	at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:840)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:320)
	at jdk.proxy4/jdk.proxy4.$Proxy201.merge(Unknown Source)
	at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:639)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
	...

Is there a way to use immutable list or is it just an overhead? If you ask me, I like things to be immutable in Java but then again, I would like to see what you guys think about this.

BR,
Hrvoje

I think I already fixed this in ORM 7.0: HHH-1914 Fix merge support for unmodifiable collections by beikov · Pull Request #9601 · hibernate/hibernate-orm · GitHub

1 Like

That’s great news! BTW My project is ready for 7 because I switch dependencies every time you release new alpha or beta and then I make all adjustments to be ready for final release. :slight_smile:
That means I can test it these days with available 7 build.

Thanks!

1 Like