Is it bug, or it just my fail? Can you explain me what is wrong?
I have created simple JPARepository
@Repository
interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);
    Collection<User> findByIdNotIn(Collection<Long> users);
}
It looks correct. And it works correct if users is not empty. But otherwise it works incorrect:
result = userRepository.findByIdNotIn([]);
It returns empty result, but it should be equals to result of findAll method call.
userRepository.findByIdNotIn([]).equals(userRepository.findAll());
To check result I have added @Query annotation to method
@Repository
interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);
    @Query('SELECT u FROM User u WHERE u.id NOT IN ?1')
    Collection<User> findByIdNotIn(Collection<Long> users);
}
And in this case expected result was correct.
Also I have tried write query using native Hibernate CriteriaBuilder
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = builder.createQuery(User.class);
Root<User> root = query.from(User.class);
query.where(builder.not(root.get("id").in([])));
result = entityManager.createQuery(query.select(root)).getResultList();
And in this case expected result was correct too.
Result Hibernate queries:
Correct result (using @Query annotation):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  ()
Incorrect result(using method naming):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  (?)
It looks like a Spring JPA bug
I spent a day in debuging spring-data-jpa source code, and I found that the problems occurs in org.springframework.data.jpa.provider.PersistenceProvider in method potentiallyConvertEmptyCollection for HIBERNATE
@Override
        public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
            return collection == null || collection.isEmpty() ? null : collection;
        }
When collection is empty this function return null value. 
But I have found, if this value replaced (at runtime) on empty collection again then the final result would be correct!!!
From JPA Specification 4.6.9 In Expressions :
There must be at least one element in the comma separated list that defines the set of values for the IN expression. If the value of a state_field_path_expression or in_item in an IN or NOT IN expression is NULL or unknown, the value of the expression is unknown.
So Spring JPA is just following JPA specification, even if, as you said, one could expect that there would be no restriction.
Best to just do the check in your business before calling the right repository method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With