From 461bc561ae824a5dbc88365cf1ee86a18e6c25a4 Mon Sep 17 00:00:00 2001 From: Kamil Krzywanski <61804231+kamilkrzywanski@users.noreply.github.com> Date: Tue, 6 Aug 2024 00:59:55 +0200 Subject: [PATCH] The transform method throws a ClassCastException when working with joinFetch since 4.4.0 (#534) * ported fix for #3264 https://github.com/querydsl/querydsl/issues/3264 from https://github.com/aasyspl/querydsl * test for regression https://github.com/querydsl/querydsl/issues/3264 * Allow test to throw exceptions when needed * Move logic for tuple creation to TupleUtils --------- Co-authored-by: sapolinarski Co-authored-by: Marvin Froeder --- .../core/group/GroupByGenericCollection.java | 5 ++++- .../core/group/GroupByGenericMap.java | 6 ++++- .../querydsl/core/group/GroupByIterate.java | 7 +++++- .../com/querydsl/core/group/GroupByMap.java | 6 ++++- .../com/querydsl/core/util/TupleUtils.java | 22 +++++++++++++++++++ .../java/com/querydsl/jpa/HibernateBase.java | 17 ++++++++++++++ 6 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 querydsl-core/src/main/java/com/querydsl/core/util/TupleUtils.java diff --git a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericCollection.java b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericCollection.java index 96a12793a2..2c8b86ae75 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericCollection.java +++ b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericCollection.java @@ -20,6 +20,7 @@ import com.querydsl.core.types.FactoryExpression; import com.querydsl.core.types.FactoryExpressionUtils; import com.querydsl.core.types.Projections; +import com.querydsl.core.util.TupleUtils; import java.util.Collection; import java.util.Objects; import java.util.function.Supplier; @@ -60,8 +61,10 @@ public RES transform(FetchableQuery query) { GroupImpl group = null; K groupId = null; while (iter.hasNext()) { + Tuple tuple = TupleUtils.toTuple(iter.next(), expressions); @SuppressWarnings("unchecked") // This type is mandated by the key type - K[] row = (K[]) iter.next().toArray(); + K[] row = (K[]) tuple.toArray(); + // end of workaround if (group == null) { group = new GroupImpl(groupExpressions, maps); groupId = row[0]; diff --git a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericMap.java b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericMap.java index a70d79df6c..b26903bfce 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericMap.java +++ b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByGenericMap.java @@ -20,6 +20,7 @@ import com.querydsl.core.types.FactoryExpression; import com.querydsl.core.types.FactoryExpressionUtils; import com.querydsl.core.types.Projections; +import com.querydsl.core.util.TupleUtils; import java.util.Map; import java.util.function.Supplier; @@ -57,8 +58,11 @@ public RES transform(FetchableQuery query) { CloseableIterator iter = query.select(expr).iterate(); try { while (iter.hasNext()) { + Tuple tuple = TupleUtils.toTuple(iter.next(), expressions); + @SuppressWarnings("unchecked") // This type is mandated by the key type - K[] row = (K[]) iter.next().toArray(); + K[] row = (K[]) tuple.toArray(); + // end of workaround K groupId = row[0]; GroupImpl group = (GroupImpl) groups.get(groupId); if (group == null) { diff --git a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByIterate.java b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByIterate.java index c844ecd612..0e20979015 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByIterate.java +++ b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByIterate.java @@ -20,6 +20,7 @@ import com.querydsl.core.types.FactoryExpression; import com.querydsl.core.types.FactoryExpressionUtils; import com.querydsl.core.types.Projections; +import com.querydsl.core.util.TupleUtils; import java.util.NoSuchElementException; import java.util.Objects; @@ -73,8 +74,12 @@ public V next() { } while (iter.hasNext()) { + // workaround from https://github.com/querydsl/querydsl/issues/3264 + Tuple tuple = TupleUtils.toTuple(iter.next(), expressions); + @SuppressWarnings("unchecked") // This type is mandated by the key type - K[] row = (K[]) iter.next().toArray(); + K[] row = (K[]) tuple.toArray(); + // end of workaround if (group == null) { group = new GroupImpl(groupExpressions, maps); groupId = row[0]; diff --git a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByMap.java b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByMap.java index 3b99170334..27e2dc5ce0 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/group/GroupByMap.java +++ b/querydsl-core/src/main/java/com/querydsl/core/group/GroupByMap.java @@ -20,6 +20,7 @@ import com.querydsl.core.types.FactoryExpression; import com.querydsl.core.types.FactoryExpressionUtils; import com.querydsl.core.types.Projections; +import com.querydsl.core.util.TupleUtils; import java.util.LinkedHashMap; import java.util.Map; @@ -51,8 +52,11 @@ public Map transform(FetchableQuery query) { } try (CloseableIterator iter = query.select(expr).iterate()) { while (iter.hasNext()) { + Tuple tuple = TupleUtils.toTuple(iter.next(), expressions); + @SuppressWarnings("unchecked") // This type is mandated by the key type - K[] row = (K[]) iter.next().toArray(); + K[] row = (K[]) tuple.toArray(); + // end of workaround K groupId = row[0]; GroupImpl group = (GroupImpl) groups.get(groupId); if (group == null) { diff --git a/querydsl-core/src/main/java/com/querydsl/core/util/TupleUtils.java b/querydsl-core/src/main/java/com/querydsl/core/util/TupleUtils.java new file mode 100644 index 0000000000..86ef005d21 --- /dev/null +++ b/querydsl-core/src/main/java/com/querydsl/core/util/TupleUtils.java @@ -0,0 +1,22 @@ +package com.querydsl.core.util; + +import com.querydsl.core.Tuple; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.Projections; + +/** TupleUtils provides tuple related utility functionality */ +public final class TupleUtils { + + public static Tuple toTuple(Object next, Expression[] expressions) { + // workaround from https://github.com/querydsl/querydsl/issues/3264 + Tuple tuple; + if (next instanceof Tuple) { + tuple = (Tuple) next; + } else if (next instanceof Object[]) { + tuple = Projections.tuple(expressions).newInstance((Object[]) next); + } else { + throw new IllegalArgumentException(String.format("Could not translate %s into tuple", next)); + } + return tuple; + } +} diff --git a/querydsl-jpa/src/test/java/com/querydsl/jpa/HibernateBase.java b/querydsl-jpa/src/test/java/com/querydsl/jpa/HibernateBase.java index 20afd93479..bfc8e7c944 100644 --- a/querydsl-jpa/src/test/java/com/querydsl/jpa/HibernateBase.java +++ b/querydsl-jpa/src/test/java/com/querydsl/jpa/HibernateBase.java @@ -14,10 +14,14 @@ package com.querydsl.jpa; import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import com.mysema.commons.lang.CloseableIterator; import com.querydsl.core.DefaultQueryMetadata; +import com.querydsl.core.Target; import com.querydsl.core.Tuple; +import com.querydsl.core.group.GroupBy; +import com.querydsl.core.testutil.ExcludeIn; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.Expression; import com.querydsl.jpa.domain.Cat; @@ -158,4 +162,17 @@ public void createQuery3() { assertTrue(row instanceof String); } } + + @Test + @ExcludeIn(Target.DERBY) + public void createQuery4() { + assertDoesNotThrow( + () -> + query() + .from(cat) + .leftJoin(cat.kittens) + .fetchJoin() + .distinct() + .transform(GroupBy.groupBy(cat.id).as(cat))); + } }