44 */
55package org .hibernate .orm .test .envers .integration .blob ;
66
7- import static org .hamcrest .MatcherAssert .assertThat ;
8- import static org .hibernate .testing .transaction .TransactionUtil .doInJPA ;
9- import static org .junit .Assert .fail ;
7+ import jakarta .persistence .Entity ;
8+ import jakarta .persistence .GeneratedValue ;
9+ import jakarta .persistence .Id ;
10+ import org .hamcrest .Matchers ;
11+ import org .hibernate .dialect .PostgreSQLDialect ;
12+ import org .hibernate .dialect .SQLServerDialect ;
13+ import org .hibernate .engine .jdbc .BlobProxy ;
14+ import org .hibernate .envers .Audited ;
15+ import org .hibernate .orm .test .envers .BaseEnversJPAFunctionalTestCase ;
16+ import org .hibernate .orm .test .envers .Priority ;
17+ import org .hibernate .testing .SkipForDialect ;
18+ import org .junit .Test ;
1019
1120import java .io .BufferedInputStream ;
1221import java .io .InputStream ;
1322import java .nio .file .Files ;
1423import java .nio .file .Path ;
1524import java .sql .Blob ;
1625
17- import org .hamcrest .Matchers ;
18- import org .hibernate .engine .jdbc .proxy .BlobProxy ;
19- import org .hibernate .envers .Audited ;
20- import org .hibernate .orm .test .envers .BaseEnversJPAFunctionalTestCase ;
21- import org .hibernate .orm .test .envers .Priority ;
22- import org .junit .Test ;
23-
24- import jakarta .persistence .Entity ;
25- import jakarta .persistence .GeneratedValue ;
26- import jakarta .persistence .Id ;
26+ import static org .hamcrest .MatcherAssert .assertThat ;
27+ import static org .hibernate .testing .transaction .TransactionUtil .doInJPA ;
28+ import static org .junit .Assert .fail ;
2729
2830/**
2931 * @author Chris Cranford
@@ -32,19 +34,19 @@ public class BasicBlobTest extends BaseEnversJPAFunctionalTestCase {
3234
3335 @ Override
3436 protected Class <?>[] getAnnotatedClasses () {
35- return new Class <?>[] { Asset .class };
37+ return new Class <?>[] {Asset .class };
3638 }
3739
3840 @ Test
3941 @ Priority (10 )
40- public void initData () {
41- final Path path = Path .of ( getClass ().getResource ( "./blob.txt" ).getPath () );
42+ public void testGenerateProxyNoStream () {
43+ final Path path = Path .of ( Thread .currentThread ().getContextClassLoader ()
44+ .getResource ( "org/hibernate/orm/test/envers/integration/blob/blob.txt" ).getPath () );
4245 doInJPA ( this ::entityManagerFactory , entityManager -> {
43- try {
44- final Asset asset = new Asset ();
45- asset .setFileName ( "blob.txt" );
46+ final Asset asset = new Asset ();
47+ asset .setFileName ( "blob.txt" );
4648
47- final InputStream stream = new BufferedInputStream ( Files .newInputStream ( path ) );
49+ try ( final InputStream stream = new BufferedInputStream ( Files .newInputStream ( path ) )) {
4850 assertThat ( stream .markSupported (), Matchers .is ( true ) );
4951
5052 // We use the method readAllBytes instead of passing the raw stream to the proxy
@@ -70,6 +72,49 @@ public void initData() {
7072 fail ( "Failed to persist the entity" );
7173 }
7274 } );
75+
76+ }
77+
78+ @ Test
79+ @ Priority (10 )
80+ @ SkipForDialect (value = PostgreSQLDialect .class ,
81+ comment = "The driver closes the stream, so it cannot be reused by envers" )
82+ @ SkipForDialect (value = SQLServerDialect .class ,
83+ comment = "The driver closes the stream, so it cannot be reused by envers" )
84+ public void testGenerateProxyStream () {
85+ final Path path = Path .of ( Thread .currentThread ().getContextClassLoader ()
86+ .getResource ( "org/hibernate/orm/test/envers/integration/blob/blob.txt" ).getPath () );
87+
88+ try (final InputStream stream = new BufferedInputStream ( Files .newInputStream ( path ) )) {
89+ doInJPA ( this ::entityManagerFactory , entityManager -> {
90+ final Asset asset = new Asset ();
91+ asset .setFileName ( "blob.txt" );
92+
93+ assertThat ( stream .markSupported (), Matchers .is ( true ) );
94+
95+ // We use the method readAllBytes instead of passing the raw stream to the proxy
96+ // since this is the only guaranteed way that will work across all dialects in a
97+ // deterministic way. Postgres and Sybase will automatically close the stream
98+ // after the blob has been written by the driver, which prevents Envers from
99+ // then writing the contents of the stream to the audit table.
100+ //
101+ // If the driver and dialect are known not to close the input stream after the
102+ // contents have been written by the driver, then it's safe to pass the stream
103+ // here instead and the stream will be automatically marked and reset so that
104+ // Envers can serialize the data after Hibernate has done so. Dialects like
105+ // H2, MySQL, Oracle, SQL Server work this way.
106+ //
107+ //
108+ Blob blob = BlobProxy .generateProxy ( stream , 9192L );
109+
110+ asset .setData ( blob );
111+ entityManager .persist ( asset );
112+ } );
113+ }
114+ catch (Exception e ) {
115+ e .printStackTrace ();
116+ fail ( "Failed to persist the entity" );
117+ }
73118 }
74119
75120 @ Audited
0 commit comments