Skip to content

Commit b4d64af

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 b4d64af

File tree

5 files changed

+86
-24
lines changed

5 files changed

+86
-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: 42 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,38 @@ private T[] fromBytes(byte[] bytes) {
376382
}
377383
}
378384

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

382407
private final Class<T> componentClass;
383408
private final MutabilityPlan<T> componentPlan;
409+
private final Class<T[]> arrayClass;
410+
private final JavaType<T> baseDescriptor;
384411

385412
public ArrayMutabilityPlan(JavaType<T> baseDescriptor) {
413+
this.baseDescriptor = baseDescriptor;
386414
this.componentClass = baseDescriptor.getJavaTypeClass();
387415
this.componentPlan = baseDescriptor.getMutabilityPlan();
416+
this.arrayClass = arrayClass( componentClass );
388417
}
389418

390419
@Override
@@ -393,16 +422,21 @@ public boolean isMutable() {
393422
}
394423

395424
@Override
396-
public T[] deepCopy(T[] value) {
425+
public T[] deepCopy(Object[] value) {
397426
if ( value == null ) {
398427
return null;
399428
}
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 ] );
429+
else {
430+
final var copy = arrayClass.cast( newInstance( componentClass, value.length ) );
431+
for ( int i = 0; i < value.length; i++ ) {
432+
copy[i] = componentPlan.deepCopy(
433+
// Horrible hack around the fact that java.sql.Timestamps
434+
// can be represented as instances of java.util.Date
435+
// (Why do we even allow this? We deprecated java.sql stuff!)
436+
baseDescriptor.coerce( value[i], null ) );
437+
}
438+
return copy;
404439
}
405-
return copy;
406440
}
407441

408442
@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)