'Spring Data Elasticsearch: ClassCastException thrown in existsBy* repository method
I've got this trivial index in ES:
{
"dynamic": "strict",
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"id": {
"type": "keyword"
},
"reviewRequestDocumentId": {
"type": "keyword"
},
"productId": {
"type": "keyword"
}
}
}
To work with it I use Spring Data Elasticsearch, so an entity and bound repository are created:
@Data
@Builder(toBuilder = true)
@Document(indexName = "order_line", createIndex = false)
public class OrderLineDocument {
@Id
private String id;
@NotNull
private String reviewRequestDocumentId;
@NotNull
private String productId;
}
public interface OrderLineRepository extends ElasticsearchRepository<OrderLineDocument, String> {
boolean existsByReviewRequestDocumentIdAndProductId(String reviewRequestDocumentId, String productId);
}
The problem I'm facing is related to repository method existsByReviewRequestDocumentIdAndProductId()
which is called from test method:
@Test
void existsByReviewRequestDocumentIdAndProductId() {
String rrdId = UUID.randomUUID().toString();
String productId = UUID.randomUUID().toString();
OrderLineDocument orderLine = OrderLineDocument.builder()
.productId(productId)
.reviewRequestDocumentId(rrdId)
.build();
String id = repository.save(orderLine).getId();
assertThat(repository.findById(id)).isNotEmpty();
assertThat(repository.existsByReviewRequestDocumentIdAndProductId(rrdId, productId)).isTrue();
}
Calling it results in ClassCastException with this stack trace:
java.lang.ClassCastException: class com.yotpo.review.requests.dashboard.core.documents.orderline.OrderLineDocument cannot be cast to class java.lang.Boolean (com.yotpo.review.requests.dashboard.core.documents.orderline.OrderLineDocument is in unnamed module of loader 'app'; java.lang.Boolean is in module java.base of loader 'bootstrap')
at com.sun.proxy.$Proxy140.existsByReviewRequestDocumentIdAndProductId(Unknown Source)
at com.yotpo.review.requests.dashboard.componenttest.OrderLineRepositoryTest.existsByReviewRequestDocumentIdAndProductId(OrderLineRepositoryTest.java:67)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
It looks like the method queries the whole entity from ES instead of fetching simple boolean
.
Does anyone aware of such issues? Is it a bug or have I misconfigured something?
P.S. I've tried also
public interface OrderLineRepository extends ElasticsearchRepository<OrderLineDocument, String> {
boolean existsOrderLineDocumentByReviewRequestDocumentIdAndProductId(String reviewRequestDocumentId, String productId);
}
same exception is thrown.
Solution 1:[1]
This is a bug, currently the fact that it is a exists method is not taken into account, and as the return type is no Collection
a normal query for the parameters is executed and the first result returned. Which leads to the error you see.
As a workaround change your method to do a count instead:
Long countOrderLineDocumentByReviewRequestDocumentIdAndProductId(String reviewRequestDocumentId, String productId);
and check if the result is greater than zero.
Thank you for reporting this issue
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | P.J.Meisch |