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-123456789012
which 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.