Skip to content

Commit a9f015e

Browse files
committed
hack around an issue with mapping arrays of Date as SQL ARRAYs
I don't know why we even need to be doing this. We deprecated that stuff. But we have one single test which is relying on this, so perhaps users are using it too.
1 parent dfef08f commit a9f015e

File tree

5 files changed

+84
-24
lines changed

5 files changed

+84
-24
lines changed

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

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import java.util.Map;
1515

1616
import org.hibernate.Hibernate;
17-
import org.hibernate.HibernateException;
1817
import org.hibernate.MappingException;
1918
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
2019
import org.hibernate.engine.spi.SessionFactoryImplementor;
@@ -268,21 +267,17 @@ public final boolean isMutable() {
268267
}
269268

270269
@Override
271-
public final Object deepCopy(Object value, SessionFactoryImplementor factory) {
272-
return deepCopy( javaType.cast( value ) );
273-
}
274-
275-
protected final T deepCopy(T value) {
276-
return getMutabilityPlan().deepCopy( value );
270+
public Object deepCopy(Object value, SessionFactoryImplementor factory) {
271+
return getMutabilityPlan().deepCopy( javaType.cast( value ) );
277272
}
278273

279274
@Override
280-
public final Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
281-
return getMutabilityPlan().disassemble( javaType.cast( value ) , session );
275+
public final Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) {
276+
return getMutabilityPlan().disassemble( javaType.cast( value ), session );
282277
}
283278

284279
@Override
285-
public final Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException {
280+
public final Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) {
286281
return getMutabilityPlan().assemble( cached, session );
287282
}
288283

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import java.util.Objects;
88

9+
import org.hibernate.engine.spi.SessionFactoryImplementor;
10+
import org.hibernate.type.descriptor.java.AbstractArrayJavaType;
911
import org.hibernate.type.descriptor.java.JavaType;
1012
import org.hibernate.type.descriptor.jdbc.JdbcType;
1113
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
@@ -16,17 +18,19 @@
1618
* @author Jordan Gigov
1719
* @author Christian Beikov
1820
*/
19-
public class BasicArrayType<T,E>
21+
public final class BasicArrayType<T,E>
2022
extends AbstractSingleColumnStandardBasicType<T>
2123
implements AdjustableBasicType<T>, BasicPluralType<T, E> {
2224

2325
private final BasicType<E> baseDescriptor;
2426
private final String name;
27+
private final AbstractArrayJavaType<T,?> arrayTypeDescriptor;
2528

2629
public BasicArrayType(BasicType<E> baseDescriptor, JdbcType arrayJdbcType, JavaType<T> arrayTypeDescriptor) {
2730
super( arrayJdbcType, arrayTypeDescriptor );
2831
this.baseDescriptor = baseDescriptor;
2932
this.name = determineArrayTypeName( baseDescriptor );
33+
this.arrayTypeDescriptor = (AbstractArrayJavaType<T, ?>) arrayTypeDescriptor;
3034
}
3135

3236
static String determineElementTypeName(BasicType<?> baseDescriptor) {
@@ -75,4 +79,26 @@ public boolean equals(Object object) {
7579
public int hashCode() {
7680
return baseDescriptor.hashCode();
7781
}
82+
83+
// Methods required to support Horrible hack around the fact
84+
// that java.sql.Timestamps in an array can be represented as
85+
// instances of java.util.Date (Why do we even allow this?)
86+
87+
@Override
88+
public boolean isEqual(Object one, Object another) {
89+
if ( one == another ) {
90+
return true;
91+
}
92+
else if ( one == null || another == null ) {
93+
return false;
94+
}
95+
else {
96+
return arrayTypeDescriptor.isEqual( one, another );
97+
}
98+
}
99+
100+
@Override
101+
public Object deepCopy(Object value, SessionFactoryImplementor factory) {
102+
return arrayTypeDescriptor.deepCopy( value );
103+
}
78104
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractArrayJavaType.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
2020
import org.hibernate.type.spi.TypeConfiguration;
2121

22+
2223
import static java.lang.reflect.Array.newInstance;
2324

2425
@AllowReflection
@@ -123,4 +124,15 @@ BasicType<T> resolveType(
123124
() -> new BasicArrayType<>( elementType, arrayJdbcType, arrayJavaType ) );
124125
}
125126

127+
// Methods required to support Horrible hack around the fact
128+
// that java.sql.Timestamps in an array can be represented as
129+
// instances of java.util.Date (Why do we even allow this?)
130+
131+
public T deepCopy(Object value) {
132+
return getMutabilityPlan().deepCopy( cast( value ) );
133+
}
134+
135+
public boolean isEqual(Object one, Object another) {
136+
return areEqual( cast( one ), cast( another) );
137+
}
126138
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ArrayJavaType.java

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public String extractLoggableRepresentation(T[] value) {
111111
}
112112

113113
@Override
114-
public boolean areEqual(T[] one, T[] another) {
114+
public boolean areEqual(Object[] one, Object[] another) {
115115
if ( one == null && another == null ) {
116116
return true;
117117
}
@@ -123,7 +123,13 @@ public boolean areEqual(T[] one, T[] another) {
123123
}
124124
int l = one.length;
125125
for ( int i = 0; i < l; i++ ) {
126-
if ( !getElementJavaType().areEqual( one[i], another[i] )) {
126+
final var elementJavaType = getElementJavaType();
127+
if ( !elementJavaType.areEqual(
128+
// Horrible hack around the fact that java.sql.Timestamps
129+
// can be represented as instances of java.util.Date
130+
// (Why do we even allow this? We deprecated java.sql stuff!)
131+
elementJavaType.coerce( one[i], null ),
132+
elementJavaType.coerce( another[i], null ) )) {
127133
return false;
128134
}
129135
}
@@ -376,15 +382,36 @@ private T[] fromBytes(byte[] bytes) {
376382
}
377383
}
378384

385+
// Methods required to support Horrible hack around the fact
386+
// that java.sql.Timestamps in an array can be represented as
387+
// instances of java.util.Date (Why do we even allow this?)
388+
389+
@Override
390+
public T[] deepCopy(Object value) {
391+
final var mutabilityPlan =
392+
(ArrayMutabilityPlan<T>)
393+
super.getMutabilityPlan();
394+
return mutabilityPlan.deepCopy( (Object[]) value );
395+
}
396+
397+
@Override
398+
public boolean isEqual(Object one, Object another) {
399+
return areEqual( (Object[]) one, (Object[]) another );
400+
}
401+
379402
@AllowReflection
380403
private static class ArrayMutabilityPlan<T> implements MutabilityPlan<T[]> {
381404

382405
private final Class<T> componentClass;
383406
private final MutabilityPlan<T> componentPlan;
407+
private final Class<T[]> arrayClass;
408+
private final JavaType<T> baseDescriptor;
384409

385410
public ArrayMutabilityPlan(JavaType<T> baseDescriptor) {
411+
this.baseDescriptor = baseDescriptor;
386412
this.componentClass = baseDescriptor.getJavaTypeClass();
387413
this.componentPlan = baseDescriptor.getMutabilityPlan();
414+
this.arrayClass = arrayClass( componentClass );
388415
}
389416

390417
@Override
@@ -393,16 +420,21 @@ public boolean isMutable() {
393420
}
394421

395422
@Override
396-
public T[] deepCopy(T[] value) {
423+
public T[] deepCopy(Object[] value) {
397424
if ( value == null ) {
398425
return null;
399426
}
400-
//noinspection unchecked
401-
final T[] copy = (T[]) newInstance( componentClass, value.length );
402-
for ( int i = 0; i < value.length; i ++ ) {
403-
copy[ i ] = componentPlan.deepCopy( value[ i ] );
427+
else {
428+
final var copy = arrayClass.cast( newInstance( componentClass, value.length ) );
429+
for ( int i = 0; i < value.length; i++ ) {
430+
copy[i] = componentPlan.deepCopy(
431+
// Horrible hack around the fact that java.sql.Timestamps
432+
// can be represented as instances of java.util.Date
433+
// (Why do we even allow this? We deprecated java.sql stuff!)
434+
baseDescriptor.coerce( value[i], null ) );
435+
}
436+
return copy;
404437
}
405-
return copy;
406438
}
407439

408440
@Override

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/array/MySqlArrayOfTimestampsTest.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.junit.jupiter.api.Test;
2323

2424
import java.sql.Timestamp;
25-
import java.time.LocalDate;
2625
import java.time.LocalDateTime;
2726
import java.time.Month;
2827
import java.util.Calendar;
@@ -109,10 +108,6 @@ public void testDate(SessionFactoryScope scope) {
109108
} );
110109
}
111110

112-
private static final LocalDateTime SUMMER = LocalDate.of( 2024, 6, 20 ).atStartOfDay();
113-
private static final LocalDateTime WINTER = LocalDate.of( 2023, 12, 22 ).atStartOfDay();
114-
private static final LocalDate EPOCH = LocalDate.of( 1970, Month.JANUARY, 1 );
115-
116111
private static final TimeZone[] TEST_TIME_ZONES = Stream.of(
117112
"Africa/Monrovia",
118113
"Europe/Zagreb",

0 commit comments

Comments
 (0)