From d57676aac02cee87ab9e703c1c10080c53acfeda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armin=20Krezovi=C4=87?= Date: Mon, 21 Jul 2025 09:52:00 +0200 Subject: [PATCH] HHH-16253 - Schema Validation Failure With Audited (N)Clob Column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://hibernate.atlassian.net/browse/HHH-16253 Signed-off-by: Armin Krezović --- .../source/internal/hbm/ModelBinder.java | 14 +-- .../lob/LargeObjectMappingTest.java | 88 +++++++++++++++++++ 2 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/lob/LargeObjectMappingTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index 544c38379a06..148e0d4c7d4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -155,6 +155,7 @@ import org.hibernate.type.CustomType; import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.ParameterizedType; @@ -1877,11 +1878,14 @@ private void resolveLob(final SingularAttributeSourceBasic attributeSource, Simp // Resolves whether the property is LOB based on the type attribute on the attribute property source. // Essentially this expects the type to map to a CLOB/NCLOB/BLOB sql type internally and compares. if ( !value.isLob() && value.getTypeName() != null ) { - final BasicType basicType = attributeSource.getBuildingContext() - .getMetadataCollector() - .getTypeConfiguration() - .getBasicTypeRegistry() - .getRegisteredType( value.getTypeName() ); + final String typeName = value.getTypeName(); + final MetadataBuildingContext context = attributeSource.getBuildingContext(); + final BasicType basicType = + typeName.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) + ? context.getBootstrapContext().resolveAdHocBasicType( typeName ) + : context.getMetadataCollector().getTypeConfiguration() + .getBasicTypeRegistry().getRegisteredType( typeName ); + if ( basicType instanceof AbstractSingleColumnStandardBasicType ) { if ( isLob( basicType.getJdbcType().getDdlTypeCode(), null ) ) { value.makeLob(); diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/lob/LargeObjectMappingTest.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/lob/LargeObjectMappingTest.java new file mode 100644 index 000000000000..5da080e81766 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/lob/LargeObjectMappingTest.java @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.envers.integration.lob; + +import java.sql.Types; +import java.util.Arrays; +import java.util.Objects; + +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.envers.Audited; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase; + +import org.hibernate.testing.orm.junit.JiraKey; +import org.junit.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import static org.junit.Assert.assertTrue; + +/** + * @author Armin Krezović (armin.krezovic at ziragroup dot com) + */ +@JiraKey(value = "HHH-16253") +public class LargeObjectMappingTest extends BaseEnversJPAFunctionalTestCase { + + @Entity + @Audited + public static class LargeObjectTestEntity { + @Id + @GeneratedValue + private Integer id; + + @JdbcTypeCode(Types.CLOB) + private String clob; + + @JdbcTypeCode(Types.BLOB) + private byte[] blob; + + public LargeObjectTestEntity() { + } + + public LargeObjectTestEntity(Integer id, String clob, byte[] blob) { + this.id = id; + this.clob = clob; + this.blob = blob; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + final LargeObjectTestEntity that = (LargeObjectTestEntity) o; + return Objects.equals( id, that.id ) && Objects.equals( + clob, + that.clob + ) && Arrays.equals( blob, that.blob ); + } + + @Override + public int hashCode() { + return Objects.hash( id, clob, Arrays.hashCode( blob ) ); + } + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { LargeObjectTestEntity.class }; + } + + @Test + public void testLobTypeMapping() { + PersistentClass entityBinding = metadata().getEntityBinding( LargeObjectTestEntity.class.getName() + "_AUD" ); + + Property blobProperty = entityBinding.getProperty( "blob" ); + Property clobProperty = entityBinding.getProperty( "clob" ); + + assertTrue( blobProperty.isLob() ); + assertTrue( clobProperty.isLob() ); + } +}