Skip to content

Commit 1d12dc0

Browse files
committed
HHH-18547, HHH-17114 add default implementations to UserType
and deprecate the wrong-signature nullSafeGet() method Signed-off-by: Gavin King <[email protected]>
1 parent 519ffb7 commit 1d12dc0

File tree

34 files changed

+174
-78
lines changed

34 files changed

+174
-78
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ public int hashCode(T x) throws HibernateException {
221221
}
222222

223223
@Override
224-
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
224+
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
225+
throws SQLException {
225226
verifyConfigured();
226227
return jdbcType.getExtractor( enumJavaType ).extract( rs, position, session );
227228
}
@@ -233,7 +234,8 @@ private void verifyConfigured() {
233234
}
234235

235236
@Override
236-
public void nullSafeSet(PreparedStatement st, T value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
237+
public void nullSafeSet(PreparedStatement st, T value, int index, SharedSessionContractImplementor session)
238+
throws SQLException {
237239
verifyConfigured();
238240
jdbcType.getBinder( enumJavaType ).bind( st, value, index, session );
239241
}

hibernate-core/src/main/java/org/hibernate/usertype/BaseUserTypeSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public int hashCode(T x) throws HibernateException {
8282
}
8383

8484
@Override
85-
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
85+
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session) throws SQLException {
8686
ensureResolved();
8787
return jdbcValueExtractor.extract( rs, position, session );
8888
}

hibernate-core/src/main/java/org/hibernate/usertype/StaticUserTypeSupport.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ public int hashCode(T x) throws HibernateException {
115115
}
116116

117117
@Override
118-
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
118+
public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
119+
throws SQLException {
119120
final Object extracted = jdbcValueExtractor.extract( rs, position, session );
120121

121122
if ( valueConverter != null ) {
@@ -127,7 +128,8 @@ public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplemento
127128
}
128129

129130
@Override
130-
public void nullSafeSet(PreparedStatement st, T value, int index, SharedSessionContractImplementor session) throws SQLException {
131+
public void nullSafeSet(PreparedStatement st, T value, int index, SharedSessionContractImplementor session)
132+
throws SQLException {
131133
final Object valueToBind;
132134
if ( valueConverter != null ) {
133135
valueToBind = valueConverter.toRelationalValue( value );

hibernate-core/src/main/java/org/hibernate/usertype/UserType.java

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.sql.PreparedStatement;
1111
import java.sql.ResultSet;
1212
import java.sql.SQLException;
13+
import java.util.Objects;
1314

1415
import org.hibernate.Incubating;
1516
import org.hibernate.dialect.Dialect;
@@ -65,9 +66,9 @@
6566
*
6667
* &#64;Override
6768
* public Period nullSafeGet(ResultSet rs, int position,
68-
* SharedSessionContractImplementor session, Object owner)
69+
* SharedSessionContractImplementor session)
6970
* throws SQLException {
70-
* String string = rs.getString( position );
71+
* String string = rs.getString(position);
7172
* return rs.wasNull() ? null : Period.parse(string);
7273
* }
7374
*
@@ -171,7 +172,7 @@
171172
*
172173
* &#64;Override
173174
* public BitSet nullSafeGet(ResultSet rs, int position,
174-
* SharedSessionContractImplementor session, Object owner)
175+
* SharedSessionContractImplementor session)
175176
* throws SQLException {
176177
* String string = rs.getString(position);
177178
* return rs.wasNull()? null : parseBitSet(columnValue);
@@ -271,35 +272,76 @@ public interface UserType<J> {
271272
* Compare two instances of the Java class mapped by this custom
272273
* type for persistence "equality", that is, equality of their
273274
* persistent state.
275+
*
276+
* @implNote The default implementation calls {@link Objects#equals}.
274277
*/
275-
boolean equals(J x, J y);
278+
default boolean equals(J x, J y) {
279+
return Objects.equals( x, y );
280+
}
276281

277282
/**
278283
* Get a hash code for the given instance of the Java class mapped
279284
* by this custom type, consistent with the definition of
280285
* {@linkplain #equals(Object, Object) persistence "equality"} for
281286
* this custom type.
287+
*
288+
* @implNote The default implementation calls {@link Objects#hashCode}.
282289
*/
283-
int hashCode(J x);
290+
default int hashCode(J x) {
291+
return Objects.hashCode( x );
292+
}
284293

285294
/**
286295
* Read an instance of the Java class mapped by this custom type
287296
* from the given JDBC {@link ResultSet}. Implementors must handle
288297
* null column values.
289298
*
290-
* @param owner in Hibernate 6, this is always null
299+
* @param owner since Hibernate 6, this is always null
300+
*
301+
* @deprecated Implement {@link #nullSafeGet(ResultSet, int, SharedSessionContractImplementor)}
291302
*/
292-
J nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, @Deprecated Object owner)
293-
throws SQLException;
303+
@Deprecated(since = "7", forRemoval = true)
304+
default J nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, @Deprecated Object owner)
305+
throws SQLException {
306+
return nullSafeGet( rs, position, session );
307+
}
308+
309+
/**
310+
* Read an instance of the Java class mapped by this custom type
311+
* from the given JDBC {@link ResultSet}. Implementors must handle
312+
* null column values.
313+
*
314+
* @implNote The default implementation calls
315+
* {@link ResultSet#getObject(int, Class)} with the
316+
* given {@code position} and with the
317+
* {@linkplain #returnedClass returned class}.
318+
*/
319+
default J nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
320+
throws SQLException {
321+
J result = rs.getObject( position, returnedClass() );
322+
return rs.wasNull() ? null : result;
323+
}
294324

295325
/**
296326
* Write an instance of the Java class mapped by this custom type
297327
* to the given JDBC {@link PreparedStatement}. Implementors must
298328
* handle null values of the Java class. A multi-column type should
299329
* be written to parameters starting from {@code index}.
330+
*
331+
* @implNote The default implementation calls
332+
* {@link PreparedStatement#setObject(int, Object, int)}
333+
* with the given {@code position} and {@code value} and
334+
* with the {@linkplain #getSqlType SQL type}.
300335
*/
301-
void nullSafeSet(PreparedStatement st, J value, int index, SharedSessionContractImplementor session)
302-
throws SQLException;
336+
default void nullSafeSet(PreparedStatement st, J value, int position, SharedSessionContractImplementor session)
337+
throws SQLException {
338+
if ( value == null ) {
339+
st.setNull( position, getSqlType() );
340+
}
341+
else {
342+
st.setObject( position, value, getSqlType() );
343+
}
344+
}
303345

304346
/**
305347
* Return a clone of the given instance of the Java class mapped
@@ -317,7 +359,8 @@ void nullSafeSet(PreparedStatement st, J value, int index, SharedSessionContract
317359
* </ul>
318360
*
319361
* @param value the object to be cloned, which may be null
320-
* @return a clone
362+
* @return a clone if the argument is mutable, or the argument if
363+
* it's an immutable object
321364
*/
322365
J deepCopy(J value);
323366

@@ -344,12 +387,25 @@ void nullSafeSet(PreparedStatement st, J value, int index, SharedSessionContract
344387
* This is an optional operation, but, if left unimplemented,
345388
* this type will not be cacheable in the second-level cache.
346389
*
390+
* @implNote The default implementation calls {@link #deepCopy}
391+
* and then casts the result to {@link Serializable}.
392+
*
347393
* @param value the object to be cached
348394
* @return a cacheable representation of the object
395+
* @throws UnsupportedOperationException if this type cannot
396+
* be cached in the second-level cache.
349397
*
350398
* @see org.hibernate.Cache
351399
*/
352-
Serializable disassemble(J value);
400+
default Serializable disassemble(J value) {
401+
if ( Serializable.class.isAssignableFrom( returnedClass() ) ) {
402+
return (Serializable) deepCopy( value );
403+
}
404+
else {
405+
throw new UnsupportedOperationException( "User-defined type '"
406+
+ getClass().getName() + "' does not override 'disassemble()'" );
407+
}
408+
}
353409

354410
/**
355411
* Reconstruct a value from its destructured representation,
@@ -364,13 +420,25 @@ void nullSafeSet(PreparedStatement st, J value, int index, SharedSessionContract
364420
* This is an optional operation, but, if left unimplemented,
365421
* this type will not be cacheable in the second-level cache.
366422
*
423+
* @implNote The default implementation calls {@link #deepCopy}.
424+
*
367425
* @param cached the object to be cached
368426
* @param owner the owner of the cached object
369427
* @return a reconstructed object from the cacheable representation
428+
* @throws UnsupportedOperationException if this type cannot
429+
* be cached in the second-level cache.
370430
*
371431
* @see org.hibernate.Cache
372432
*/
373-
J assemble(Serializable cached, Object owner);
433+
default J assemble(Serializable cached, Object owner) {
434+
if ( returnedClass().isInstance( cached) ) {
435+
return deepCopy( (J) cached );
436+
}
437+
else {
438+
throw new UnsupportedOperationException( "User-defined type '"
439+
+ getClass().getName() + "' does not override 'assemble()'" );
440+
}
441+
}
374442

375443
/**
376444
* During merge, replace the existing (target) value in the

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/embeddables/DollarValueUserType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public int hashCode(DollarValue x) throws HibernateException {
4242
}
4343

4444
@Override
45-
public DollarValue nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
45+
public DollarValue nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
46+
throws SQLException {
4647
return new DollarValue( rs.getBigDecimal( position ) );
4748
}
4849

@@ -51,7 +52,7 @@ public void nullSafeSet(
5152
PreparedStatement st,
5253
DollarValue value,
5354
int index,
54-
SharedSessionContractImplementor session) throws HibernateException, SQLException {
55+
SharedSessionContractImplementor session) throws SQLException {
5556
st.setBigDecimal(index, value.getAmount());
5657
}
5758

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/embeddables/MyDateUserType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public int hashCode(MyDate x) throws HibernateException {
4242
}
4343

4444
@Override
45-
public MyDate nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
45+
public MyDate nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
46+
throws SQLException {
4647
return new MyDate( rs.getDate( position ) );
4748
}
4849

@@ -51,7 +52,7 @@ public void nullSafeSet(
5152
PreparedStatement st,
5253
MyDate value,
5354
int index,
54-
SharedSessionContractImplementor session) throws HibernateException, SQLException {
55+
SharedSessionContractImplementor session) throws SQLException {
5556
st.setDate(index, new java.sql.Date(value.getDate().getTime()));
5657
}
5758

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/custom_types/FirstLetterType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public int getSqlType() {
2626
}
2727

2828
@Override
29-
public FirstLetter nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
29+
public FirstLetter nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
30+
throws SQLException {
3031
String persistValue = (String) rs.getObject( position );
3132
if ( rs.wasNull() ) {
3233
return null;
@@ -36,7 +37,7 @@ public FirstLetter nullSafeGet(ResultSet rs, int position, SharedSessionContract
3637

3738
@Override
3839
public void nullSafeSet(PreparedStatement st, FirstLetter value, int index, SharedSessionContractImplementor session)
39-
throws HibernateException, SQLException {
40+
throws SQLException {
4041
if ( value == null ) {
4142
st.setNull( index, getSqlType() );
4243
}

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/enumerated/custom_types/LastNumberType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public int getSqlType() {
2626
}
2727

2828
@Override
29-
public LastNumber nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
29+
public LastNumber nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
30+
throws SQLException {
3031
String persistValue = (String) rs.getObject( position );
3132
if ( rs.wasNull() ) {
3233
return null;
@@ -36,7 +37,7 @@ public LastNumber nullSafeGet(ResultSet rs, int position, SharedSessionContractI
3637

3738
@Override
3839
public void nullSafeSet(PreparedStatement st, LastNumber value, int index, SharedSessionContractImplementor session)
39-
throws HibernateException, SQLException {
40+
throws SQLException {
4041
if ( value == null ) {
4142
st.setNull( index, getSqlType() );
4243
}

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/StateType.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,16 @@ public int hashCode(State x) throws HibernateException {
4141
}
4242

4343
@Override
44-
public State nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
44+
public State nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
45+
throws SQLException {
4546
int result = rs.getInt( position );
4647
if ( rs.wasNull() ) return null;
4748
return State.values()[result];
4849
}
4950

5051
@Override
51-
public void nullSafeSet(PreparedStatement st, State value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
52+
public void nullSafeSet(PreparedStatement st, State value, int index, SharedSessionContractImplementor session)
53+
throws HibernateException, SQLException {
5254
if (value == null) {
5355
st.setNull( index, Types.INTEGER );
5456
}

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/MyGenericType.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ public void setParameterValues(Properties params) {
5151
}
5252

5353
@Override
54-
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws SQLException {
54+
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
55+
throws SQLException {
5556
st.setString( index, null );
5657
}
5758

5859
@Override
59-
public Object nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
60+
public Object nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session)
61+
throws SQLException {
6062
return null;
6163
}
6264

0 commit comments

Comments
 (0)