Skip to content

Spring Data Elasticsearch: ClassCastException thrown in existsBy* repository method #2162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
stsypanov opened this issue May 13, 2022 · 2 comments · Fixed by #2236
Closed
Labels
type: bug A general bug

Comments

@stsypanov
Copy link

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);

}

and

public interface OrderLineRepository extends ElasticsearchRepository<OrderLineDocument, String> {

    boolean existsOrderLineByReviewRequestDocumentIdAndProductId(String reviewRequestDocumentId, String productId);

}

same exception is thrown.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 13, 2022
@sothawo
Copy link
Collaborator

sothawo commented May 13, 2022

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.

@sothawo sothawo added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels May 13, 2022
@stsypanov
Copy link
Author

Cool, looking forward for this to be fixed!

sothawo added a commit to sothawo/spring-data-elasticsearch that referenced this issue Jul 22, 2022
sothawo added a commit that referenced this issue Jul 22, 2022
sothawo added a commit that referenced this issue Jul 22, 2022
Original Pull Request #2236
Closes #2162

(cherry picked from commit 373be49)
sothawo added a commit that referenced this issue Jul 22, 2022
Original Pull Request #2236
Closes #2162

(cherry picked from commit 373be49)
(cherry picked from commit be70a39)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants