diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java index 7f9bd36d53..57e92aa0ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/BlobProxy.java @@ -31,6 +31,8 @@ import org.hibernate.type.descriptor.java.DataHelper; public final class BlobProxy implements Blob, BlobImplementer { private final BinaryStream binaryStream; + private final int markBytes; + private boolean resetAllowed; private boolean needsReset; /** @@ -41,6 +43,8 @@ public final class BlobProxy implements Blob, BlobImplementer { */ private BlobProxy(byte[] bytes) { binaryStream = new BinaryStreamImpl( bytes ); + markBytes = bytes.length + 1; + setStreamMark(); } /** @@ -52,6 +56,18 @@ public final class BlobProxy implements Blob, BlobImplementer { */ private BlobProxy(InputStream stream, long length) { this.binaryStream = new StreamBackedBinaryStream( stream, length ); + this.markBytes = (int) length + 1; + setStreamMark(); + } + + private void setStreamMark() { + if ( binaryStream.getInputStream().markSupported() ) { + binaryStream.getInputStream().mark( markBytes ); + resetAllowed = true; + } + else { + resetAllowed = false; + } } @@ -67,7 +83,12 @@ public final class BlobProxy implements Blob, BlobImplementer { private void resetIfNeeded() throws SQLException { try { if ( needsReset ) { + if ( !resetAllowed ) { + throw new SQLException( "Underlying stream does not allow reset" ); + } + binaryStream.getInputStream().reset(); + setStreamMark(); } } catch ( IOException ioe) { diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/BasicBlobTest.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/BasicBlobTest.java new file mode 100644 index 0000000000..29621bad2a --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/BasicBlobTest.java @@ -0,0 +1,98 @@ +/* + * 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 . + */ +package org.hibernate.orm.test.envers.integration.blob; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.fail; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Blob; + +import org.hamcrest.Matchers; +import org.hibernate.engine.jdbc.BlobProxy; +import org.hibernate.envers.Audited; +import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase; +import org.hibernate.orm.test.envers.Priority; +import org.junit.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +/** + * @author Chris Cranford + */ +public class BasicBlobTest extends BaseEnversJPAFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Asset.class }; + } + + @Test + @Priority(10) + public void initData() { + final Path path = Path.of( getClass().getResource( "./blob.txt" ).getPath() ); + doInJPA( this::entityManagerFactory, entityManager -> { + try { + final Asset asset = new Asset(); + asset.setFileName( "blob.txt" ); + + final InputStream stream = new BufferedInputStream( Files.newInputStream( path ) ); + assertThat( stream.markSupported(), Matchers.is( true ) ); + + Blob blob = BlobProxy.generateProxy( stream, Files.size( path ) ); + + asset.setData( blob ); + entityManager.persist( asset ); + } + catch (Exception e) { + e.printStackTrace(); + fail( "Failed to persist the entity" ); + } + } ); + } + + @Audited + @Entity(name = "Asset") + public static class Asset { + @Id + @GeneratedValue + private Integer id; + private String fileName; + private Blob data; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Blob getData() { + return data; + } + + public void setData(Blob data) { + this.data = data; + } + } + +} diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/blob.txt b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/blob.txt new file mode 100644 index 0000000000..a1a2ab6acc --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/blob/blob.txt @@ -0,0 +1,33 @@ + + + + + + + create-drop + + false + false + + org.hibernate.dialect.H2Dialect + jdbc:h2:mem:envers + org.h2.Driver + sa + + + + + + + + + + +