Tested with latest 6.6.0-SNAPSHOT
:
org.hibernate.query.sqm.produce.function.FunctionArgumentException: Parameter 0 of function 'array_contains()' requires an array type, but argument is of type 'java.lang.String[]'
at org.hibernate.dialect.function.array.ArrayArgumentValidator.getPluralType(ArrayArgumentValidator.java:64)
at org.hibernate.dialect.function.array.ArrayContainsArgumentValidator.validate(ArrayContainsArgumentValidator.java:35)
at org.hibernate.query.sqm.produce.function.StandardArgumentsValidators$8.lambda$validate$0(StandardArgumentsValidators.java:254)
at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4204)
at org.hibernate.query.sqm.produce.function.StandardArgumentsValidators$8.validate(StandardArgumentsValidators.java:254)
at org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor.generateSqmExpression(AbstractSqmFunctionDescriptor.java:102)
at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.function(SqmCriteriaNodeBuilder.java:1732)
at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.function(SqmCriteriaNodeBuilder.java:190)
at com.example.demo.PostgreSQLTests.test(PostgreSQLTests.java:87)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Here is the test case:
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.TestPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
@DataJpaTest
@EntityScan(basePackageClasses = PostgreSQLArrayTests.class)
@EnableJpaRepositories(considerNestedRepositories = true)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@TestPropertySource(properties = { "spring.jpa.hibernate.ddl-auto=update",
"logging.level.org.hibernate.orm.jdbc.bind=TRACE" })
public class PostgreSQLArrayTests {
@Autowired
EntityManager entityManager;
@Test
void arrayContains() {
TestEntity entity = new TestEntity();
entity.tags = Set.of("foo", "bar");
entityManager.persist(entity);
entityManager.flush();
entityManager.clear();
TestEntity persisted = entityManager.find(TestEntity.class, entity.id);
assertThat(persisted.tags).isEqualTo(entity.tags);
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<TestEntity> cq = cb.createQuery(TestEntity.class);
Root<TestEntity> root = cq.from(TestEntity.class);
cq.where(cb.isTrue(cb.function("array_contains", Boolean.class,
cb.function("string_to_array", String[].class, root.get("tags"), cb.literal(",")), cb.literal("foo"))));
assertThat(entityManager.createQuery(cq).getResultList()).hasSize(1);
}
public static interface TestEntityRepository
extends JpaRepository<TestEntity, Long>, JpaSpecificationExecutor<TestEntity> {
}
@Configuration
@ImportAutoConfiguration(classes = ServiceConnectionAutoConfiguration.class)
static class Config {
@Bean
@ServiceConnection
PostgreSQLContainer<?> container() {
return new PostgreSQLContainer<>("postgres");
}
}
@Entity
public static class TestEntity {
@Id
@GeneratedValue
Long id;
@Convert(converter = SetConverter.class)
Set<String> tags;
}
static class SetConverter implements AttributeConverter<Set<String>, String> {
@Override
public String convertToDatabaseColumn(Set<String> attribute) {
if (attribute == null)
return null;
return String.join(",", attribute);
}
@Override
public Set<String> convertToEntityAttribute(String dbData) {
if (dbData == null)
return null;
Set<String> result = new LinkedHashSet<>();
result.addAll(Set.of(dbData.split(",")));
return result;
}
}
}