Skip to content
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

QuerydslDefaultBinding should unwrap nested collections for IN binding #2834

Closed
rxxy opened this issue May 24, 2023 · 7 comments
Closed

QuerydslDefaultBinding should unwrap nested collections for IN binding #2834

rxxy opened this issue May 24, 2023 · 7 comments
Assignees
Labels
type: bug A general bug

Comments

@rxxy
Copy link

rxxy commented May 24, 2023

when i bind the parameter on a property of type set

The predicate expected to be generated:
id in sysUser.departments

The actual generated predicate
[id] in sysUser.departments

This problem works fine in hibernate5, but throws an exception in hibernate6

2023-05-24 10:32:17.650 ERROR [http-nio-8083-exec-8]  at com.teamytd.config.web.UnknownExceptionNotice.commonException(UnknownExceptionNotice.java:32) - java.lang.ClassCastException: class java.util.LinkedHashSet cannot be cast to class java.lang.String (java.util.LinkedHashSet and java.lang.String are in module java.base of loader 'bootstrap')
	at org.hibernate.type.descriptor.java.StringJavaType.unwrap(StringJavaType.java:27)
	at org.hibernate.type.descriptor.jdbc.VarcharJdbcType$1.doBind(VarcharJdbcType.java:108)
	at org.hibernate.type.descriptor.jdbc.BasicBinder.bind(BasicBinder.java:61)
...

entity:

public class SysUser {
    ...
    private Set<SysDepartment> departments;
    ...
}

controller argument:

departments: 297e00ad8848850e0188488987d70013

image
image

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 24, 2023
@mp911de
Copy link
Member

mp911de commented May 30, 2023

To help you to diagnose the problem, please spend some time providing a minimal sample that reproduces the problem.

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label May 30, 2023
@rxxy
Copy link
Author

rxxy commented May 31, 2023

To help you to diagnose the problem, please spend some time providing a minimal sample that reproduces the problem.

see https://github.com/rxxy/springdatacommons-issue2834

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 31, 2023
@mp911de
Copy link
Member

mp911de commented Jun 1, 2023

The HQL query is:

select sysUser
from SysUser sysUser
where (?1) member of sysUser.departments

The exception stack trace is:

java.lang.ClassCastException: class java.util.LinkedHashSet cannot be cast to class java.lang.Long (java.util.LinkedHashSet and java.lang.Long are in module java.base of loader 'bootstrap')
	at org.hibernate.type.descriptor.java.LongJavaType.unwrap(LongJavaType.java:24) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.type.descriptor.jdbc.BigIntJdbcType$1.doBind(BigIntJdbcType.java:62) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.type.descriptor.jdbc.BasicBinder.bind(BasicBinder.java:61) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.internal.AbstractJdbcParameter.bindParameterValue(AbstractJdbcParameter.java:117) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.internal.AbstractJdbcParameter.bindParameterValue(AbstractJdbcParameter.java:107) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.bindParameters(DeferredResultSetAccess.java:199) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.executeQuery(DeferredResultSetAccess.java:228) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.getResultSet(DeferredResultSetAccess.java:163) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advanceNext(JdbcValuesResultSetImpl.java:204) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:84) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:29) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:65) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:198) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:362) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:109) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:518) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at org.hibernate.query.Query.getResultList(Query.java:119) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
	at com.querydsl.jpa.impl.AbstractJPAQuery.getResultList(AbstractJPAQuery.java:191) ~[querydsl-jpa-5.0.0-jakarta.jar:na]
	at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(AbstractJPAQuery.java:243) ~[querydsl-jpa-5.0.0-jakarta.jar:na]

This is either a Querydsl or a Hibernate issue as the Querydsl code in Spring Data hasn't changed and Querydsl is creating the actual query.

@mp911de mp911de closed this as not planned Won't fix, can't repro, duplicate, stale Jun 1, 2023
@mp911de mp911de added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Jun 1, 2023
@rxxy
Copy link
Author

rxxy commented Jun 2, 2023

The parsed predicateis [2] in sysUser.departments
The correct predicateshould be 2 in sysUser.departments

[2] In sysUser.departments should be a malformation, hibernate5.x is compatible with such a malformation.

I think it would be better to adjust to normal predicate, wouldn't it?

@rxxy
Copy link
Author

rxxy commented Jun 2, 2023

select sysUser
from SysUser sysUser
where (?1) member of sysUser.departments

HQL is correct, but the parameter should be an entity object, not a Set

@mp911de mp911de reopened this Jun 2, 2023
@mp911de mp911de added type: bug A general bug and removed for: external-project For an external project and not something we can fix labels Jun 2, 2023
@mp911de mp911de changed the title Problem with QuerydslDefaultBinding when the field is of type Set QuerydslPredicateBuilder converts elements of set to Collection<Set<T>> instead of Collection<T> Jun 2, 2023
@mp911de mp911de self-assigned this Jun 2, 2023
@mp911de
Copy link
Member

mp911de commented Jun 2, 2023

You're right, that Hibernate leniently accepted Set<Set<…>> and now it no longer does. We need to fix the issue.

@mp911de mp911de changed the title QuerydslPredicateBuilder converts elements of set to Collection<Set<T>> instead of Collection<T> QuerydslDefaultBinding should unwrap nested collections for IN binding Jun 2, 2023
@mp911de
Copy link
Member

mp911de commented Jun 2, 2023

QuerydslPredicateBuilder is able to convert Foo,Bar into a collection containing Foo and Bar elements. This also works for a single element that is wrapped into a collection-type. We should not break this behavior.

It makes rather sense to unwrap nested collections in QuerydslDefaultBinding if a path is CollectionPathBase. Bindings can be overridden and we likely break less things that way.

mp911de added a commit that referenced this issue Jun 2, 2023
When binding values to collection-like paths, we now unwrap potentially double-wrapped collections as QuerydslPredicateBuilder attempts to convert the binding value to the type of the path.

Our default is a contains binding for single elements.

Closes #2834
@mp911de mp911de closed this as completed in bfcb2ff Jun 2, 2023
mp911de added a commit that referenced this issue Jun 2, 2023
When binding values to collection-like paths, we now unwrap potentially double-wrapped collections as QuerydslPredicateBuilder attempts to convert the binding value to the type of the path.

Our default is a contains binding for single elements.

Closes #2834
@mp911de mp911de added this to the 3.0.7 (2022.0.7) milestone Jun 2, 2023
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

No branches or pull requests

3 participants