From 890e4ad62c1d9757c5181c1496efacff6460f24b Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 25 Jan 2023 18:26:52 +0100 Subject: [PATCH] HHH-16040 New coercing assembler when types are different from expected --- .../internal/BasicAttributeMapping.java | 8 ++- .../BasicEntityIdentifierMappingImpl.java | 6 +- .../internal/SimpleForeignKeyDescriptor.java | 9 ++- .../sql/results/graph/basic/BasicFetch.java | 56 +++++++++++++++++-- .../sql/results/graph/basic/BasicResult.java | 33 ++++++++++- .../graph/basic/BasicResultAssembler.java | 4 +- .../graph/basic/CoercingResultAssembler.java | 38 +++++++++++++ .../java/PrimitiveCharacterArrayJavaType.java | 5 ++ .../type/descriptor/java/StringJavaType.java | 7 +++ .../orm/test/jpa/criteria/TreatPathTest.java | 30 +++++----- .../CharArrayToStringJoinColumnTest.java | 40 +++++++++++-- .../StringToCharArrayJoinColumnTest.java | 41 ++++++++++++-- ...ringInEmbeddedJoinColumnOrFormulaTest.java | 4 +- ...ArrayToStringInEmbeddedJoinColumnTest.java | 40 +++++++++++-- ...tringInEmbeddedMultipleJoinColumnTest.java | 40 +++++++++++-- ...ngToCharArrayInEmbeddedJoinColumnTest.java | 40 +++++++++++-- ...ArrayInEmbeddedMultipleJoinColumnTest.java | 40 +++++++++++-- 17 files changed, 375 insertions(+), 66 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/CoercingResultAssembler.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java index 2f56b9ec4b..545d84b32c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java @@ -360,6 +360,7 @@ public class BasicAttributeMapping // Lazy property. A valuesArrayPosition of -1 will lead to // returning a domain result assembler that returns LazyPropertyInitializer.UNFETCHED_PROPERTY final EntityMappingType containingEntityMapping = findContainingEntityMapping(); + boolean coerceResultType = false; if ( fetchTiming == FetchTiming.DELAYED && !( fetchParent instanceof EmbeddableResultGraphNode ) && containingEntityMapping.getEntityPersister().getPropertyLaziness()[getStateArrayPosition()] ) { @@ -375,6 +376,10 @@ public class BasicAttributeMapping final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState ); valuesArrayPosition = sqlSelection.getValuesArrayPosition(); + if ( sqlSelection.getExpressionType() != null) { + // if the expression type is different that the expected type coerce the value + coerceResultType = sqlSelection.getExpressionType().getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType(); + } } return new BasicFetch<>( @@ -383,7 +388,8 @@ public class BasicAttributeMapping fetchablePath, this, fetchTiming, - creationState + creationState, + coerceResultType ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index 3fac7df21b..0eaef6effe 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.model.domain.NavigableRole; @@ -399,13 +400,16 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa assert tableGroup != null; final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, false, fetchParent, creationState ); + final JdbcMappingContainer selectionType = sqlSelection.getExpressionType(); return new BasicFetch<>( sqlSelection.getValuesArrayPosition(), fetchParent, fetchablePath, this, FetchTiming.IMMEDIATE, - creationState + creationState, + // if the expression type is different that the expected type coerce the value + selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != getJdbcMapping().getJdbcJavaType() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index 9f49802cb2..73744c492b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.ModelPart; @@ -316,17 +317,21 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa ); } + final JavaType javaType = selectableMapping.getJdbcMapping().getJdbcJavaType(); final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection( sqlExpressionResolver.resolveSqlExpression( tableReference, selectableMapping ), - selectableMapping.getJdbcMapping().getJdbcJavaType(), + javaType, fetchParent, sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration() ); + final JdbcMappingContainer selectionType = sqlSelection.getExpressionType(); return new BasicResult<>( sqlSelection.getValuesArrayPosition(), null, - selectableMapping.getJdbcMapping() + selectableMapping.getJdbcMapping(), + // if the expression type is different that the expected type coerce the value + selectionType != null && selectionType.getSingleJdbcMapping().getJdbcJavaType() != javaType ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicFetch.java index eca9b3c3fe..ef5f747f84 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicFetch.java @@ -55,6 +55,28 @@ public class BasicFetch implements Fetch, BasicResultGraphNode { ); } + public BasicFetch( + int valuesArrayPosition, + FetchParent fetchParent, + NavigablePath fetchablePath, + BasicValuedModelPart valuedMapping, + FetchTiming fetchTiming, + DomainResultCreationState creationState, + boolean coerceResultType) { + //noinspection unchecked + this( + valuesArrayPosition, + fetchParent, + fetchablePath, + valuedMapping, + (BasicValueConverter) valuedMapping.getJdbcMapping().getValueConverter(), + fetchTiming, + true, + creationState, + coerceResultType + ); + } + public BasicFetch( int valuesArrayPosition, FetchParent fetchParent, @@ -84,6 +106,29 @@ public class BasicFetch implements Fetch, BasicResultGraphNode { FetchTiming fetchTiming, boolean canBasicPartFetchBeDelayed, DomainResultCreationState creationState) { + this( + valuesArrayPosition, + fetchParent, + fetchablePath, + valuedMapping, + valueConverter, + fetchTiming, + canBasicPartFetchBeDelayed, + creationState, + false + ); + } + + public BasicFetch( + int valuesArrayPosition, + FetchParent fetchParent, + NavigablePath fetchablePath, + BasicValuedModelPart valuedMapping, + BasicValueConverter valueConverter, + FetchTiming fetchTiming, + boolean canBasicPartFetchBeDelayed, + DomainResultCreationState creationState, + boolean coerceResultType) { this.navigablePath = fetchablePath; this.fetchParent = fetchParent; @@ -100,11 +145,12 @@ public class BasicFetch implements Fetch, BasicResultGraphNode { } } else { - this.assembler = new BasicResultAssembler<>( - valuesArrayPosition, - javaType, - valueConverter - ); + if (coerceResultType) { + this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); + } + else { + this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResult.java index 46cfe41166..7329d8520c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResult.java @@ -41,6 +41,22 @@ public class BasicResult implements DomainResult, BasicResultGraphNode ); } + public BasicResult( + int jdbcValuesArrayPosition, + String resultVariable, + JdbcMapping jdbcMapping, + boolean coerceResultType) { + //noinspection unchecked + this( + jdbcValuesArrayPosition, + resultVariable, + jdbcMapping.getJavaTypeDescriptor(), + jdbcMapping.getValueConverter(), + null, + coerceResultType + ); + } + public BasicResult( int jdbcValuesArrayPosition, String resultVariable, @@ -85,11 +101,26 @@ public class BasicResult implements DomainResult, BasicResultGraphNode JavaType javaType, BasicValueConverter valueConverter, NavigablePath navigablePath) { + this( valuesArrayPosition, resultVariable, javaType, valueConverter, navigablePath, false ); + } + + public BasicResult( + int valuesArrayPosition, + String resultVariable, + JavaType javaType, + BasicValueConverter valueConverter, + NavigablePath navigablePath, + boolean coerceResultType) { this.resultVariable = resultVariable; this.javaType = javaType; this.navigablePath = navigablePath; - this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); + if ( coerceResultType ) { + this.assembler = new CoercingResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); + } + else { + this.assembler = new BasicResultAssembler<>( valuesArrayPosition, javaType, valueConverter ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResultAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResultAssembler.java index 75c707ca02..06a8d94806 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResultAssembler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResultAssembler.java @@ -26,8 +26,8 @@ public class BasicResultAssembler implements DomainResultAssembler { return new BasicResultAssembler<>( selection.getValuesArrayPosition(), javaType ); } - private final int valuesArrayPosition; - private final JavaType assembledJavaType; + protected final int valuesArrayPosition; + protected final JavaType assembledJavaType; private final BasicValueConverter valueConverter; public BasicResultAssembler( diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/CoercingResultAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/CoercingResultAssembler.java new file mode 100644 index 0000000000..810355cd66 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/CoercingResultAssembler.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.graph.basic; + +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; +import org.hibernate.type.descriptor.java.JavaType; + +/** + * A {@link BasicResultAssembler} which does type coercion to handle cases + * where the expression type and the expected result {@link JavaType} are different + * (e.g. same column mapped with differently typed properties). + * + * @author Marco Belladelli + */ +public class CoercingResultAssembler extends BasicResultAssembler { + public CoercingResultAssembler( + int valuesArrayPosition, + JavaType assembledJavaType, + BasicValueConverter valueConverter) { + super( valuesArrayPosition, assembledJavaType, valueConverter ); + } + + /** + * Access to the row value, coerced to expected type + */ + @Override + public Object extractRawValue(RowProcessingState rowProcessingState) { + return assembledJavaType.coerce( + rowProcessingState.getJdbcValue( valuesArrayPosition ), + rowProcessingState.getSession() + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java index 89f849b682..2f09bdb59c 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/PrimitiveCharacterArrayJavaType.java @@ -92,4 +92,9 @@ public class PrimitiveCharacterArrayJavaType extends AbstractClassJavaType char[] coerce(X value, CoercionContext coercionContext) { + return wrap( value, null ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java index cd75777494..517d2a9bcf 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/StringJavaType.java @@ -90,6 +90,9 @@ public class StringJavaType extends AbstractClassJavaType { if (value instanceof String) { return (String) value; } + if (value instanceof char[]) { + return new String( (char[]) value ); + } if (value instanceof Reader) { return DataHelper.extractString( (Reader) value ); } @@ -113,4 +116,8 @@ public class StringJavaType extends AbstractClassJavaType { } } + @Override + public String coerce(X value, CoercionContext coercionContext) { + return wrap( value, null ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatPathTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatPathTest.java index dbc460d46a..e64f608a08 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatPathTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatPathTest.java @@ -42,6 +42,7 @@ import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Marco Belladelli @@ -65,7 +66,7 @@ public class TreatPathTest { term.setLength( 4 ); term.setLanguage( language ); term.setAnyProperty( stringProperty ); - term.setSynonyms( new ArrayList<>( List.of( "ciao" ) ) ); + term.setSynonyms( new ArrayList<>() ); term.setEmbeddableProperty( new EmbeddableType( "ciao" ) ); Linkage linkage = new Linkage(); linkage.setTerm( term ); @@ -101,14 +102,7 @@ public class TreatPathTest { @Test public void testTreatPluralValue(EntityManagerFactoryScope scope) { - scope.inTransaction( entityManager -> { - try { - testCriteriaTreat( entityManager, "synonyms", List.of( "ciao" ) ); - } - catch (Exception e) { - assertEquals( UnsupportedOperationException.class, e.getClass() ); - } - } ); + scope.inTransaction( entityManager -> testCriteriaTreat( entityManager, "synonyms", null, true ) ); } @Test @@ -129,13 +123,17 @@ public class TreatPathTest { } private void testCriteriaTreat(EntityManager entityManager, String property, Object value) { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery criteria = cb.createQuery( Linkage.class ); - Root root = criteria.from( Linkage.class ); - Path asLocalTerm = cb.treat( root.get( "term" ), LocalTerm.class ); - Predicate predicate; - if ( value instanceof Collection ) { - predicate = asLocalTerm.get( property ).in( value ); + testCriteriaTreat( entityManager, property, value, false ); + } + + private void testCriteriaTreat(EntityManager entityManager, String property, Object value, boolean plural) { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery criteria = cb.createQuery( Linkage.class ); + final Root root = criteria.from( Linkage.class ); + final Path asLocalTerm = cb.treat( root.get( "term" ), LocalTerm.class ); + final Predicate predicate; + if ( plural ) { + predicate = cb.isEmpty( asLocalTerm.get( property ) ); } else { predicate = cb.equal( asLocalTerm.get( property ), value ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/CharArrayToStringJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/CharArrayToStringJoinColumnTest.java index ae6db6cf1c..1866a71831 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/CharArrayToStringJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/CharArrayToStringJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -23,6 +24,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -43,10 +45,10 @@ public class CharArrayToStringJoinColumnTest { vehicle.setId( 1L ); vehicle.setStringProp( "2020" ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( "2020".toCharArray() ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -62,13 +64,24 @@ public class CharArrayToStringJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() ); + } ); + } + + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId() ) ); } ); } @@ -107,6 +120,13 @@ public class CharArrayToStringJoinColumnTest { @Column(name = "string_col", nullable = false) private String stringProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -122,6 +142,14 @@ public class CharArrayToStringJoinColumnTest { public void setStringProp(String stringProp) { this.stringProp = stringProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/StringToCharArrayJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/StringToCharArrayJoinColumnTest.java index 2ac91d2d79..7f6a58e9c7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/StringToCharArrayJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/StringToCharArrayJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -23,6 +24,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -43,10 +45,10 @@ public class StringToCharArrayJoinColumnTest { vehicle.setId( 1L ); vehicle.setCharArrayProp( "2020".toCharArray() ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( "2020" ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -62,16 +64,28 @@ public class StringToCharArrayJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() )); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) ); } ); } + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId() ); + } ); + } + + @Entity(name = "VehicleInvoice") public static class VehicleInvoice { @Id @@ -107,6 +121,13 @@ public class StringToCharArrayJoinColumnTest { @Column(name = "char_array_col", nullable = false) private char[] charArrayProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -122,6 +143,14 @@ public class StringToCharArrayJoinColumnTest { public void setCharArrayProp(char[] charArrayProp) { this.charArrayProp = charArrayProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnOrFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnOrFormulaTest.java index 63284df042..b03bacd613 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnOrFormulaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnOrFormulaTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.joincolumn; +package org.hibernate.orm.test.mapping.joincolumn.embedded; import java.io.Serializable; @@ -101,7 +101,7 @@ public class CharArrayToStringInEmbeddedJoinColumnOrFormulaTest { @ManyToOne(fetch = FetchType.EAGER) @JoinColumnsOrFormulas({ - @JoinColumnOrFormula(formula = @JoinFormula(value = "trim(char_array_col_1)", referencedColumnName = "string_col_1")), + @JoinColumnOrFormula(formula = @JoinFormula(value = "char_array_col_1", referencedColumnName = "string_col_1")), @JoinColumnOrFormula(column = @JoinColumn(name = "char_array_col_2", referencedColumnName = "string_col_2", insertable = false, updatable = false)) }) private Vehicle vehicle; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnTest.java index d89c258233..d649be48ca 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn.embedded; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -25,6 +26,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,10 +47,10 @@ public class CharArrayToStringInEmbeddedJoinColumnTest { vehicle.setId( 1L ); vehicle.setStringProp( "2020" ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -64,13 +66,24 @@ public class CharArrayToStringInEmbeddedJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() ); + } ); + } + + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId().getCharArrayProp() ) ); } ); } @@ -141,6 +154,13 @@ public class CharArrayToStringInEmbeddedJoinColumnTest { @Column(name = "string_col", nullable = false) private String stringProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -156,6 +176,14 @@ public class CharArrayToStringInEmbeddedJoinColumnTest { public void setStringProp(String stringProp) { this.stringProp = stringProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedMultipleJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedMultipleJoinColumnTest.java index a711b03ee5..837c9153c1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedMultipleJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/CharArrayToStringInEmbeddedMultipleJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn.embedded; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -25,6 +26,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,10 +48,10 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest { vehicle.setStringProp( "2020" ); vehicle.setIntProp( 2020 ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( new VehicleInvoiceId( "2020".toCharArray(), 2020 ) ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -65,13 +67,24 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", resultList.get( 0 ).getVehicle().getStringProp() ); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", vehicleInvoice.getVehicle().getStringProp() ); + } ); + } + + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", new String( vehicle.getInvoices().get( 0 ).getId().getCharArrayProp() ) ); } ); } @@ -146,6 +159,13 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest { @Column(name = "int_col", nullable = false) private int intProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -169,6 +189,14 @@ public class CharArrayToStringInEmbeddedMultipleJoinColumnTest { public void setIntProp(int intProp) { this.intProp = intProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedJoinColumnTest.java index 6f8134851f..8d2ed27cd9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn.embedded; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -25,6 +26,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,10 +47,10 @@ public class StringToCharArrayInEmbeddedJoinColumnTest { vehicle.setId( 1L ); vehicle.setCharArrayProp( "2020".toCharArray() ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( new VehicleInvoiceId( "2020", 2020 ) ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -64,13 +66,24 @@ public class StringToCharArrayInEmbeddedJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() ) ); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) ); + } ); + } + + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId().getStringProp() ); } ); } @@ -141,6 +154,13 @@ public class StringToCharArrayInEmbeddedJoinColumnTest { @Column(name = "char_array_col", nullable = false) private char[] charArrayProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -156,6 +176,14 @@ public class StringToCharArrayInEmbeddedJoinColumnTest { public void setCharArrayProp(char[] charArrayProp) { this.charArrayProp = charArrayProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedMultipleJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedMultipleJoinColumnTest.java index db4afd2d87..91733df566 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedMultipleJoinColumnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/joincolumn/embedded/StringToCharArrayInEmbeddedMultipleJoinColumnTest.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.mapping.joincolumn.embedded; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import org.hibernate.testing.orm.junit.DomainModel; @@ -25,6 +26,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,10 +48,10 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest { vehicle.setCharArrayProp( "2020".toCharArray() ); vehicle.setIntProp( 2020 ); session.persist( vehicle ); - VehicleInvoice invoice = new VehicleInvoice(); invoice.setId( new VehicleInvoiceId( "2020", 2020 ) ); invoice.setVehicle( vehicle ); + vehicle.getInvoices().add( invoice ); session.persist( invoice ); } ); } @@ -65,13 +67,24 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest { @Test public void testAssociation(SessionFactoryScope scope) { scope.inTransaction( session -> { - List resultList = session.createQuery( + final VehicleInvoice vehicleInvoice = session.createQuery( "from VehicleInvoice", VehicleInvoice.class - ).getResultList(); - assertEquals( 1, resultList.size() ); - assertEquals( 1L, resultList.get( 0 ).getVehicle().getId() ); - assertEquals( "2020", new String( resultList.get( 0 ).getVehicle().getCharArrayProp() )); + ).getSingleResult(); + assertEquals( 1L, vehicleInvoice.getVehicle().getId() ); + assertEquals( "2020", new String( vehicleInvoice.getVehicle().getCharArrayProp() ) ); + } ); + } + + @Test + public void testInverse(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Vehicle vehicle = session.createQuery( + "from Vehicle", + Vehicle.class + ).getSingleResult(); + assertEquals( 1, vehicle.getInvoices().size() ); + assertEquals( "2020", vehicle.getInvoices().get( 0 ).getId().getStringProp() ); } ); } @@ -146,6 +159,13 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest { @Column(name = "int_col", nullable = false) private int intProp; + @OneToMany(mappedBy = "vehicle") + private List invoices; + + public Vehicle() { + this.invoices = new ArrayList<>(); + } + public Long getId() { return id; } @@ -169,6 +189,14 @@ public class StringToCharArrayInEmbeddedMultipleJoinColumnTest { public void setIntProp(int intProp) { this.intProp = intProp; } + + public List getInvoices() { + return invoices; + } + + public void setInvoices(List invoices) { + this.invoices = invoices; + } } }