Skip to content

Commit 1af8781

Browse files
committed
HHH-12555 Fix merging of lazy loaded blobs/clobs/nclobs
It's better to avoid pushing UNFETCHED_PROPERTY to the types as it requires all the types to take it into account. TypeHelper looks like the only sensible caller that needs change.
1 parent c79ce44 commit 1af8781

File tree

6 files changed

+91
-26
lines changed

6 files changed

+91
-26
lines changed

hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,7 @@ protected MutabilityPlan<T> getMutabilityPlan() {
7171
}
7272

7373
protected T getReplacement(T original, T target, SharedSessionContractImplementor session) {
74-
if ( original == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
75-
return target;
76-
}
77-
else if ( !isMutable() ||
78-
( target != LazyPropertyInitializer.UNFETCHED_PROPERTY && isEqual( original, target ) ) ) {
74+
if ( !isMutable() || ( target != null && isEqual( original, target ) ) ) {
7975
return original;
8076
}
8177
else {
@@ -351,6 +347,10 @@ public final Type getSemiResolvedType(SessionFactoryImplementor factory) {
351347
@Override
352348
@SuppressWarnings({ "unchecked" })
353349
public final Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) {
350+
if ( original == null && target == null ) {
351+
return null;
352+
}
353+
354354
return getReplacement( (T) original, (T) target, session );
355355
}
356356

hibernate-core/src/main/java/org/hibernate/type/BlobType.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
package org.hibernate.type;
88

99
import java.sql.Blob;
10+
import java.sql.SQLException;
1011

12+
import org.hibernate.engine.jdbc.LobCreator;
13+
import org.hibernate.engine.jdbc.spi.JdbcServices;
1114
import org.hibernate.engine.spi.SharedSessionContractImplementor;
15+
import org.hibernate.internal.util.collections.ArrayHelper;
1216
import org.hibernate.type.descriptor.java.BlobTypeDescriptor;
1317

1418
/**
@@ -36,7 +40,23 @@ protected boolean registerUnderJavaType() {
3640

3741
@Override
3842
protected Blob getReplacement(Blob original, Blob target, SharedSessionContractImplementor session) {
43+
if ( target == null ) {
44+
return copyOriginalBlob( (Blob) original, session );
45+
}
46+
3947
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeBlob( original, target, session );
4048
}
4149

50+
private Blob copyOriginalBlob(Blob original, SharedSessionContractImplementor session) {
51+
try {
52+
final LobCreator lobCreator = session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getLobCreator(
53+
session );
54+
return original == null
55+
? lobCreator.createBlob( ArrayHelper.EMPTY_BYTE_ARRAY )
56+
: lobCreator.createBlob( original.getBinaryStream(), original.length() );
57+
}
58+
catch (SQLException e) {
59+
throw session.getJdbcServices().getSqlExceptionHelper().convert( e, "unable to merge BLOB data" );
60+
}
61+
}
4262
}

hibernate-core/src/main/java/org/hibernate/type/ClobType.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
package org.hibernate.type;
88

99
import java.sql.Clob;
10+
import java.sql.SQLException;
1011

12+
import org.hibernate.engine.jdbc.LobCreator;
13+
import org.hibernate.engine.jdbc.spi.JdbcServices;
1114
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1215
import org.hibernate.type.descriptor.java.ClobTypeDescriptor;
1316

@@ -36,7 +39,21 @@ protected boolean registerUnderJavaType() {
3639

3740
@Override
3841
protected Clob getReplacement(Clob original, Clob target, SharedSessionContractImplementor session) {
39-
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeClob( original, target, session );
42+
if ( target == null ) {
43+
return copyOriginalClob( (Clob) original, session );
44+
}
45+
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeClob( (Clob) original, (Clob) target, session );
4046
}
4147

48+
private Clob copyOriginalClob(Clob original, SharedSessionContractImplementor session) {
49+
try {
50+
final LobCreator lobCreator = session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getLobCreator( session );
51+
return original == null
52+
? lobCreator.createClob( "" )
53+
: lobCreator.createClob( original.getCharacterStream(), original.length() );
54+
}
55+
catch (SQLException e) {
56+
throw session.getJdbcServices().getSqlExceptionHelper().convert( e, "unable to merge CLOB data" );
57+
}
58+
}
4259
}

hibernate-core/src/main/java/org/hibernate/type/NClobType.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
package org.hibernate.type;
88

99
import java.sql.NClob;
10+
import java.sql.SQLException;
1011

12+
import org.hibernate.engine.jdbc.LobCreator;
13+
import org.hibernate.engine.jdbc.spi.JdbcServices;
1114
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1215
import org.hibernate.type.descriptor.java.NClobTypeDescriptor;
1316

1417
/**
15-
* A type that maps between {@link java.sql.Types#CLOB CLOB} and {@link java.sql.Clob}
18+
* A type that maps between {@link java.sql.Types#NCLOB NCLOB} and {@link java.sql.NClob}
1619
*
1720
* @author Gavin King
1821
* @author Steve Ebersole
@@ -36,7 +39,21 @@ protected boolean registerUnderJavaType() {
3639

3740
@Override
3841
protected NClob getReplacement(NClob original, NClob target, SharedSessionContractImplementor session) {
42+
if ( target == null ) {
43+
return copyOriginalNClob( original, session );
44+
}
3945
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeNClob( original, target, session );
4046
}
4147

48+
private NClob copyOriginalNClob(NClob original, SharedSessionContractImplementor session) {
49+
try {
50+
final LobCreator lobCreator = session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getLobCreator( session );
51+
return original == null
52+
? lobCreator.createNClob( "" )
53+
: lobCreator.createNClob( original.getCharacterStream(), original.length() );
54+
}
55+
catch (SQLException e) {
56+
throw session.getJdbcServices().getSqlExceptionHelper().convert( e, "unable to merge NCLOB data" );
57+
}
58+
}
4259
}

hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ public static Object[] replace(
159159
if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || original[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
160160
copied[i] = target[i];
161161
}
162+
else if ( target[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
163+
copied[i] = types[i].replace( original[i], null, session, owner, copyCache );
164+
}
162165
else {
163166
copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache );
164167
}
@@ -193,6 +196,9 @@ public static Object[] replace(
193196
|| original[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
194197
copied[i] = target[i];
195198
}
199+
else if ( target[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
200+
copied[i] = types[i].replace( original[i], null, session, owner, copyCache, foreignKeyDirection );
201+
}
196202
else {
197203
copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection );
198204
}

hibernate-core/src/test/java/org/hibernate/test/type/TypeTest.java

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66
*/
77
package org.hibernate.test.type;
88

9+
import static org.junit.Assert.assertFalse;
10+
import static org.junit.Assert.assertNotEquals;
11+
import static org.junit.Assert.assertSame;
12+
import static org.junit.Assert.assertTrue;
13+
14+
import java.io.Serializable;
15+
import java.math.BigDecimal;
16+
import java.math.BigInteger;
17+
import java.sql.Time;
18+
import java.sql.Timestamp;
19+
import java.util.Calendar;
20+
import java.util.Currency;
21+
import java.util.GregorianCalendar;
22+
import java.util.Locale;
23+
import java.util.SimpleTimeZone;
24+
import java.util.TimeZone;
25+
926
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
1027
import org.hibernate.internal.SessionImpl;
1128
import org.hibernate.internal.util.SerializationHelper;
@@ -42,26 +59,11 @@
4259
import org.hibernate.type.TimeZoneType;
4360
import org.hibernate.type.TimestampType;
4461
import org.hibernate.type.TrueFalseType;
62+
import org.hibernate.type.Type;
63+
import org.hibernate.type.TypeHelper;
4564
import org.hibernate.type.YesNoType;
4665
import org.junit.Test;
4766

48-
import java.io.Serializable;
49-
import java.math.BigDecimal;
50-
import java.math.BigInteger;
51-
import java.sql.Time;
52-
import java.sql.Timestamp;
53-
import java.util.Calendar;
54-
import java.util.Currency;
55-
import java.util.GregorianCalendar;
56-
import java.util.Locale;
57-
import java.util.SimpleTimeZone;
58-
import java.util.TimeZone;
59-
60-
import static org.junit.Assert.assertFalse;
61-
import static org.junit.Assert.assertNotEquals;
62-
import static org.junit.Assert.assertSame;
63-
import static org.junit.Assert.assertTrue;
64-
6567
/**
6668
* @author Steve Ebersole
6769
*/
@@ -344,8 +346,11 @@ protected <T> void runBasicTests(AbstractSingleColumnStandardBasicType<T> type,
344346
assertTrue( original == type.replace( original, copy, null, null, null ) );
345347

346348
// following tests assert that types work with properties not yet loaded in bytecode enhanced entities
347-
assertSame( copy, type.replace( LazyPropertyInitializer.UNFETCHED_PROPERTY, copy, null, null, null ) );
348-
assertNotEquals( LazyPropertyInitializer.UNFETCHED_PROPERTY, type.replace( original, LazyPropertyInitializer.UNFETCHED_PROPERTY, null, null, null ) );
349+
Type[] types = new Type[]{ type };
350+
assertSame( copy, TypeHelper.replace( new Object[]{ LazyPropertyInitializer.UNFETCHED_PROPERTY },
351+
new Object[]{ copy }, types, null, null, null )[0] );
352+
assertNotEquals( LazyPropertyInitializer.UNFETCHED_PROPERTY, TypeHelper.replace( new Object[]{ original },
353+
new Object[]{ LazyPropertyInitializer.UNFETCHED_PROPERTY }, types, null, null, null )[0] );
349354

350355
assertTrue( type.isSame( original, copy ) );
351356
assertTrue( type.isEqual( original, copy ) );

0 commit comments

Comments
 (0)