0

After migration from spring-data-jpa 2.7.1 to 3.1.2 (SpringBoot 3.1.2 migration) in method:

@Query("""
    SELECT o
    FROM Storage o
    WHERE o.status = 'SUCCESS'
    AND (
        (:referenceNumbers) IS NULL
        OR o.referenceNumber IN (:referenceNumbers)
    )
    ...
""")
Page<Storage> findObject(ObjectFilter filter, Set<String> referenceNumbers, Iterable<Long> systemIds, Pageable pageable);
@Entity
@Getter
@Setter
@RequiredArgsConstructor
@EqualsAndHashCode
@Accessors(chain = true)
class Storage {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String referenceNumber;

    @Enumerated(EnumType.STRING)
    private Status status;
}

I'm getting:

org.springframework.orm.jpa.JpaSystemException: Unknown wrap conversion requested: java.util.ImmutableCollections$Set12 to java.lang.String : org.hibernate.type.descriptor.java.StringJavaType (java.lang.String)

Seems like IN method is not able to handle Collection anymore

I was trying to find documentation for JPQL IN method but could not find anything relevant.

For Spring Data JPA 2.7.1, this method was working perfectly fine.

I tried to find documentation for the IN method for Spring Data JPA 3.1.2, because I have many similar methods in project and my app might be working with many databases (PostgreSQL, Oracle).

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Jakub K
  • 1
  • 1
  • Can you show your `Object`? I assume you are not referring to `java.lang.Object` but something else you just called `Object` in your question for demonstration. Maybe try removing the brackets around `:referenceNumbers`. – dan1st Aug 08 '23 at 07:15
  • It doesn't compile without ':' – Jakub K Aug 08 '23 at 07:34
  • I am not talking about the colon but the parenthesis around it. – dan1st Aug 08 '23 at 07:38
  • Does it work if you don't have the `IS NULL` check? Does that effect the exception? – dan1st Aug 08 '23 at 07:40
  • IN (:referenceNumbers) - > IN :referenceNumbers doesn't make any difference but without IS NULL it's working :) – Jakub K Aug 08 '23 at 08:00
  • Does the exception also occur with the `IS NULL` but without the `IN`? – dan1st Aug 08 '23 at 08:03

1 Answers1

0

It seems like the (:referenceNumbers) IS NULL is the problem. You can split the query method in two methods, one with custom logic for handling that:

@Query("SELECT o FROM Storage o WHERE o.status = 'SUCCESS' " +
" AND (:ignoreReferenceNumbers OR o.referenceNumber IN (:referenceNumbers)) " +"...")
Page<Storage> findObjectInternal(ObjectFilter filter, Set<String> referenceNumbers, boolean ignoreReferenceNumbers, Iterable<Long> systemIdsPageable pageable);

default Page<Storage> findObject(ObjectFilter filter, Set<String> referenceNumbers, Iterable<Long> systemIds,Pageable pageable){
    if(referenceNumbers==null){
        return findObjectInternal(filter, Collections.emptyList(), true, systemIds, pageable);
    }
    return findObjectInternal(filter, referenceNumbers, false, systemIds, pageable);
}

or use two (overloaded) default methods:

@Query("SELECT o FROM Storage o WHERE o.status = 'SUCCESS' " +
" AND (:ignoreReferenceNumbers OR o.referenceNumber IN (:referenceNumbers)) " +"...")
Page<Storage> findObjectInternal(ObjectFilter filter, Set<String> referenceNumbers, boolean ignoreReferenceNumbers, Iterable<Long> systemIdsPageable pageable);

default Page<Storage> findObject(ObjectFilter filter, Set<String> referenceNumbers, Iterable<Long> systemIds,Pageable pageable){
    return findObjectInternal(filter, referenceNumbers, false, systemIds, pageable);
}

default Page<Storage> findObject(ObjectFilter filter, Iterable<Long> systemIds,Pageable pageable){
    return findObjectInternal(filter, Collections.emptyList(), true, systemIds, pageable);
}

and always call the corresponding default method instead of using a null argument. As mentioned by the OP in the comments, it is also possible like this:

@Query("SELECT o FROM Storage o WHERE o.status = 'SUCCESS' " +
" AND (coalesce(:#{#referenceNumbers}, null) IS NULL OR o.referenceNumber IN (:referenceNumbers)) " +"...")
Page<Storage> findObject(ObjectFilter filter, Set<String> referenceNumbers, Iterable<Long> systemIds,Pageable pageable);
dan1st
  • 12,568
  • 8
  • 34
  • 67
  • This solution will work, but in some queries in a code I have 3 lines like this eg: (:referenceNumbers1) IS NULL OR o.referenceNumber1 IN (:referenceNumbers1) AND (:referenceNumbers2) IS NULL OR o.referenceNumber2 IN (:referenceNumbers2) AND (:referenceNumbers3) IS NULL OR o.referenceNumber3 IN (:referenceNumbers3), if solution won't work well here but at least I know that is null is causing this problem – Jakub K Aug 08 '23 at 10:36
  • `" AND (coalesce(:#{#referenceNumbers}, null) IS NULL OR o.referenceNumber IN (:referenceNumbers) )" ` this approach solved my problem !!! ;) – Jakub K Aug 08 '23 at 10:55