HHH-14725 Fix reset handling on BlobProxy
This commit is contained in:
parent
fefadfe6ea
commit
9525ac7fd2
|
@ -40,6 +40,8 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
||||||
// no longer necessary. The class name could be updated to reflect this but that would break APIs.
|
// no longer necessary. The class name could be updated to reflect this but that would break APIs.
|
||||||
|
|
||||||
private final BinaryStream binaryStream;
|
private final BinaryStream binaryStream;
|
||||||
|
private final int markBytes;
|
||||||
|
private boolean resetAllowed;
|
||||||
private boolean needsReset;
|
private boolean needsReset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,6 +52,8 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
||||||
*/
|
*/
|
||||||
private BlobProxy(byte[] bytes) {
|
private BlobProxy(byte[] bytes) {
|
||||||
binaryStream = new ArrayBackedBinaryStream( bytes );
|
binaryStream = new ArrayBackedBinaryStream( bytes );
|
||||||
|
markBytes = bytes.length + 1;
|
||||||
|
setStreamMark();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +65,18 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
||||||
*/
|
*/
|
||||||
private BlobProxy(InputStream stream, long length) {
|
private BlobProxy(InputStream stream, long length) {
|
||||||
this.binaryStream = new StreamBackedBinaryStream( stream, 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getStream() throws SQLException {
|
private InputStream getStream() throws SQLException {
|
||||||
|
@ -76,7 +92,12 @@ public final class BlobProxy implements Blob, BlobImplementer {
|
||||||
private void resetIfNeeded() throws SQLException {
|
private void resetIfNeeded() throws SQLException {
|
||||||
try {
|
try {
|
||||||
if ( needsReset ) {
|
if ( needsReset ) {
|
||||||
|
if ( !resetAllowed ) {
|
||||||
|
throw new SQLException( "Underlying stream does not allow reset" );
|
||||||
|
}
|
||||||
|
|
||||||
binaryStream.getInputStream().reset();
|
binaryStream.getInputStream().reset();
|
||||||
|
setStreamMark();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( IOException ioe) {
|
catch ( IOException ioe) {
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
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.proxy.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
~ Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
-->
|
||||||
|
<!DOCTYPE hibernate-configuration PUBLIC
|
||||||
|
"-//Hibernate/Hibernate Configuration DTD//EN"
|
||||||
|
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
|
||||||
|
|
||||||
|
<hibernate-configuration>
|
||||||
|
<session-factory>
|
||||||
|
<property name="hbm2ddl.auto">create-drop</property>
|
||||||
|
|
||||||
|
<property name="show_sql">false</property>
|
||||||
|
<property name="format_sql">false</property>
|
||||||
|
|
||||||
|
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
|
||||||
|
<property name="connection.url">jdbc:h2:mem:envers</property>
|
||||||
|
<property name="connection.driver_class">org.h2.Driver</property>
|
||||||
|
<property name="connection.username">sa</property>
|
||||||
|
<property name="connection.password"></property>
|
||||||
|
|
||||||
|
<!--<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>-->
|
||||||
|
<!--<property name="connection.url">jdbc:mysql:///hibernate_tests?useUnicode=true&characterEncoding=UTF-8</property>-->
|
||||||
|
<!--<property name="connection.driver_class">com.mysql.jdbc.Driver</property>-->
|
||||||
|
<!--<property name="connection.username">root</property>-->
|
||||||
|
<!--<property name="connection.password"></property>-->
|
||||||
|
|
||||||
|
<!--<property name="hibernate.jdbc.batch_size">100</property>-->
|
||||||
|
</session-factory>
|
||||||
|
</hibernate-configuration>
|
Loading…
Reference in New Issue