Skip to content

Commit c06bf74

Browse files
committed
WIP JPA Criteria aliasing fix
1 parent bb3f263 commit c06bf74

File tree

4 files changed

+190
-1
lines changed

4 files changed

+190
-1
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.jpa.spi;
8+
9+
import org.hibernate.transform.BasicTransformerAdapter;
10+
import org.hibernate.transform.ResultTransformer;
11+
12+
public class AliasInjectingTransformer extends BasicTransformerAdapter {
13+
14+
private final String[] aliases;
15+
private final ResultTransformer resultTransformer;
16+
17+
public AliasInjectingTransformer(String[] aliases, ResultTransformer resultTransformer) {
18+
this.aliases = aliases;
19+
this.resultTransformer = resultTransformer;
20+
}
21+
22+
public String[] getAliases() {
23+
return aliases;
24+
}
25+
26+
@Override
27+
public Object transformTuple(Object[] tuple, String[] aliases) {
28+
return resultTransformer.transformTuple(tuple, this.aliases);
29+
}
30+
}

hibernate-core/src/main/java/org/hibernate/jpa/spi/CriteriaQueryTupleTransformer.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ public CriteriaQueryTupleTransformer(List<ValueHandlerFactory.ValueHandler> valu
2828
this.tupleElements = tupleElements;
2929
}
3030

31+
public String[] getAliases() {
32+
final String[] aliases = new String[this.tupleElements.size()];
33+
for (int i = 0; i < aliases.length; i++) {
34+
aliases[i] = ((TupleElement<?>) this.tupleElements.get(i)).getAlias();
35+
}
36+
return aliases;
37+
}
38+
3139
@Override
3240
public Object transformTuple(Object[] tuple, String[] aliases) {
3341
final Object[] valueHandlerResult;

hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969
import org.hibernate.jpa.internal.util.ConfigurationHelper;
7070
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
7171
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
72+
import org.hibernate.jpa.spi.AliasInjectingTransformer;
73+
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
7274
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
7375
import org.hibernate.property.access.spi.Getter;
7476
import org.hibernate.property.access.spi.PropertyAccess;
@@ -929,7 +931,21 @@ else if ( retType.isArray() ) {
929931
@Override
930932
@SuppressWarnings("unchecked")
931933
public QueryImplementor setResultTransformer(ResultTransformer transformer) {
932-
this.resultTransformer = transformer;
934+
if ( this.resultTransformer instanceof CriteriaQueryTupleTransformer ) {
935+
this.resultTransformer = new AliasInjectingTransformer(
936+
((CriteriaQueryTupleTransformer) this.resultTransformer).getAliases(),
937+
transformer
938+
);
939+
}
940+
else if ( this.resultTransformer instanceof AliasInjectingTransformer ) {
941+
this.resultTransformer = new AliasInjectingTransformer(
942+
((AliasInjectingTransformer) this.resultTransformer).getAliases(),
943+
transformer
944+
);
945+
}
946+
else {
947+
this.resultTransformer = transformer;
948+
}
933949
return this;
934950
}
935951

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.jpa.test.criteria;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.ObjectInputStream;
12+
import java.io.ObjectOutput;
13+
import java.io.ObjectOutputStream;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import javax.persistence.Tuple;
17+
import javax.persistence.TypedQuery;
18+
import javax.persistence.criteria.CriteriaBuilder;
19+
import javax.persistence.criteria.CriteriaQuery;
20+
import javax.persistence.criteria.Root;
21+
import javax.persistence.metamodel.EntityType;
22+
23+
import org.hibernate.CacheMode;
24+
import org.hibernate.ScrollMode;
25+
import org.hibernate.ScrollableResults;
26+
import org.hibernate.Session;
27+
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
28+
import org.hibernate.jpa.test.callbacks.RemoteControl;
29+
import org.hibernate.jpa.test.callbacks.Television;
30+
import org.hibernate.jpa.test.callbacks.VideoSystem;
31+
import org.hibernate.jpa.test.inheritance.Fruit;
32+
import org.hibernate.jpa.test.inheritance.Strawberry;
33+
import org.hibernate.jpa.test.metamodel.Address;
34+
import org.hibernate.jpa.test.metamodel.Alias;
35+
import org.hibernate.jpa.test.metamodel.Country;
36+
import org.hibernate.jpa.test.metamodel.CreditCard;
37+
import org.hibernate.jpa.test.metamodel.Customer;
38+
import org.hibernate.jpa.test.metamodel.Info;
39+
import org.hibernate.jpa.test.metamodel.LineItem;
40+
import org.hibernate.jpa.test.metamodel.Order;
41+
import org.hibernate.jpa.test.metamodel.Phone;
42+
import org.hibernate.jpa.test.metamodel.Product;
43+
import org.hibernate.jpa.test.metamodel.ShelfLife;
44+
import org.hibernate.jpa.test.metamodel.Spouse;
45+
import org.hibernate.query.spi.QueryImplementor;
46+
import org.hibernate.transform.ResultTransformer;
47+
48+
import org.hibernate.testing.TestForIssue;
49+
import org.hibernate.testing.transaction.TransactionUtil;
50+
import org.junit.Assert;
51+
import org.junit.Before;
52+
import org.junit.Test;
53+
54+
import static org.hamcrest.CoreMatchers.notNullValue;
55+
import static org.hamcrest.CoreMatchers.nullValue;
56+
import static org.hamcrest.core.Is.is;
57+
import static org.junit.Assert.assertThat;
58+
59+
public class CriteriaAliasTest extends BaseEntityManagerFunctionalTestCase {
60+
@Override
61+
public Class[] getAnnotatedClasses() {
62+
return new Class[] {
63+
Customer.class,
64+
Alias.class,
65+
Phone.class,
66+
Address.class,
67+
Country.class,
68+
CreditCard.class,
69+
Info.class,
70+
Spouse.class,
71+
LineItem.class,
72+
Order.class,
73+
Product.class,
74+
ShelfLife.class,
75+
// @Inheritance
76+
Fruit.class,
77+
Strawberry.class,
78+
// @MappedSuperclass
79+
VideoSystem.class,
80+
Television.class,
81+
RemoteControl.class
82+
};
83+
}
84+
85+
@Before
86+
public void setUp(){
87+
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
88+
Customer customer = new Customer();
89+
customer.setId( "id" );
90+
customer.setName( " David R. Vincent " );
91+
entityManager.persist( customer );
92+
} );
93+
}
94+
95+
@Test
96+
@TestForIssue(jiraKey = "HHH-")
97+
public void testAliasJPACriteriaQuery() {
98+
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
99+
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
100+
final CriteriaQuery<Tuple> query = criteriaBuilder.createTupleQuery();
101+
final Root<Customer> from = query.from( Customer.class );
102+
query.multiselect(
103+
from.get( "id" ),
104+
from.get( "name" ).alias( "my.name" ),
105+
from.get( "age" ).alias( "alter" )
106+
);
107+
108+
final MyResultTransformer transformer = new MyResultTransformer();
109+
entityManager.createQuery( query )
110+
.unwrap( QueryImplementor.class )
111+
.setResultTransformer( transformer )
112+
.getResultList();
113+
assertThat( transformer.aliases, is(notNullValue()) );
114+
assertThat( transformer.aliases.length, is( 3 ) );
115+
assertThat( transformer.aliases[0], is(nullValue()) );
116+
assertThat( transformer.aliases[1], is( "my.name" ) );
117+
assertThat( transformer.aliases[2], is( "alter" ) );
118+
} );
119+
}
120+
121+
private static class MyResultTransformer implements ResultTransformer {
122+
String[] aliases;
123+
124+
@Override
125+
public Object transformTuple(Object[] tuple, String[] aliases) {
126+
this.aliases = aliases;
127+
return tuple;
128+
}
129+
130+
@Override
131+
public List transformList(List collection) {
132+
return collection;
133+
}
134+
}
135+
}

0 commit comments

Comments
 (0)