Spring Data cannot fetch a record using UUID in postgresql

Sayak Mukhopadhyay :

I am using Spring data to manage a REST API. All tables in my postgresql database has a primary key of type UUID. I am able to persist this data but unable to fetch it. Below is the code I am using and the problem I am facing.

MyTableParent.java

@MappedSuperclass
public class MyTableParent {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(
            name = "uuid",
            strategy = "com.mypackage.UUIDGenerator",
            parameters = {
                    @Parameter(
                            name = UUID_NAMESPACE,
                            value = "something"
                    )
            }
    )
    private UUID id;
    // Constructor getter setter
}

MyTable.java

@Entity
@Table(name = "my_table")
public class MyTable extends MyTableParent {
    private String name;
    // constructor getter setter
}

This is my service class for the table

TableService.java

@Service("tableservice")
public class TableService {
    private TableRepository tableRepository;

    public TableService(TableRepository tableRepository) {
        this.tableRepository = tableRepository;
    }

    public List<MyTable> read(MultiValueMap<String, String> queryParams) {
        return this.tableRepository.findAll(TableSpecification.searchByParams(queryParams));
    }

    public MyTable read(UUID id) {
        return this.tableRepository.findById(id).orElse(null);
    }
}

As you can see I am using a repository object as well as a specification. I have defined the repository as such

@Repository
interface TableRepository extends JpaRepository<MyTable, UUID>, JpaSpecificationExecutor<MyTable> {
}

And the specification is created as

public class TableSpecification {
    public static <T> Specification<T> searchByParams(MultiValueMap<String, String> queryMap) {
        return (Specification<T>) (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> {
            Set<Map.Entry<String, List<String>>> fields = queryMap.entrySet();
            if (queryMap.size() != 0) {
                List<Predicate> predicates = new ArrayList<>();
                for (MultiValueMap.Entry<String, List<String>> field : fields) {
                    List<String> params = new ArrayList<>(field.getValue());
                    String property = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, field.getKey());
                    Expression<String> expression = root.get(property);
                    predicates.add(expression.in(params));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
            }
            return null;
        };
    }
}

The first issue arises when I call read(MultiValueMap). Say I have my request params as /my_table?id=12345678-1234-1234-1234-123456789012which triggers the code this.tableRepository.findAll(TableSpecification.searchByParams(queryParams)) where queryParams the MultiValueMap. This is throwing an error

java.lang.IllegalArgumentException: Parameter value [12345678-1234-1234-1234-123456789012] did not match expected type [java.util.UUID (n/a)]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.internal.QueryParameterBindingImpl.validate(QueryParameterBindingImpl.java:90) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.internal.QueryParameterBindingImpl.setBindValue(QueryParameterBindingImpl.java:55) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.internal.AbstractProducedQuery.setParameter(AbstractProducedQuery.java:486) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.internal.AbstractProducedQuery.setParameter(AbstractProducedQuery.java:104) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.criteria.internal.compile.CriteriaCompiler$1$1.bind(CriteriaCompiler.java:119) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.criteria.internal.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:368) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:149) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3616) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at com.sun.proxy.$Proxy125.createQuery(Unknown Source) ~[na:na]...

So I tried to check the findById method. This is causing this.tableRepository.findById(id).orElse(null) to return null which means that the find failed too.

I am at a loss how to proceed with this. Please advise.

N.B. I can fetch records by the name field correctly. I have a hunch that spring data is messing up the types somewhere.

EDIT Not working even for String type field.

Karol Dowbecki :

The Parameter value [12345678-1234-1234-1234-123456789012] did not match expected type [java.util.UUID (n/a)] error means that value read from the database failed to map to the corresponding field type.

See HHH-9562 Dialect specific UUID handling which improved UUID handling in Hibernate 5. Your problem might be solvable with @Column(columnDefinition = "uuid", updatable = false) annotation.

@Id
@Column(columnDefinition = "uuid", updatable = false)
@GeneratedValue(generator = "uuid")
@GenericGenerator(
        name = "uuid",
        strategy = "com.mypackage.UUIDGenerator",
        parameters = {
                @Parameter(
                        name = UUID_NAMESPACE,
                        value = "something"
                )
        }
)
private UUID id;

If you need to debug it further check PostgreSQL Dialect class that you configured in your code and ensure that field definition in your entity correctly declares PostgreSQL UUID column type. There have been a number of issues with UUID e.g. HHH-9577.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=460855&siteId=1