Skip to content

Commit 38777d8

Browse files
committed
HHH-19906 JSON serialization: handle non-array values for array types
1 parent 98ab8f0 commit 38777d8

File tree

1 file changed

+85
-33
lines changed

1 file changed

+85
-33
lines changed

hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/spi/JsonGeneratingVisitor.java

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
1616
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
1717
import org.hibernate.type.BasicType;
18-
import org.hibernate.type.SqlTypes;
1918
import org.hibernate.type.descriptor.WrapperOptions;
2019
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
2120
import org.hibernate.type.descriptor.java.JavaType;
@@ -27,6 +26,7 @@
2726

2827
import java.io.IOException;
2928
import java.lang.reflect.Array;
29+
import java.util.Collection;
3030

3131
import static org.hibernate.type.descriptor.jdbc.StructHelper.getSubPart;
3232

@@ -37,7 +37,8 @@ public class JsonGeneratingVisitor {
3737

3838
public static final JsonGeneratingVisitor INSTANCE = new JsonGeneratingVisitor();
3939

40-
protected JsonGeneratingVisitor() {}
40+
protected JsonGeneratingVisitor() {
41+
}
4142

4243
/**
4344
* Serializes an array of values into JSON object/array
@@ -56,40 +57,82 @@ public void visitArray(JavaType<?> elementJavaType, JdbcType elementJdbcType, Ob
5657
}
5758

5859
if ( elementJdbcType instanceof JsonJdbcType jsonElementJdbcType ) {
59-
final EmbeddableMappingType embeddableMappingType = jsonElementJdbcType.getEmbeddableMappingType();
60-
for ( Object value : values ) {
60+
visitPluralAggregateValues( jsonElementJdbcType, values, options, writer );
61+
}
62+
else {
63+
assert !(elementJdbcType instanceof AggregateJdbcType);
64+
visitBasicPluralValues( elementJavaType, elementJdbcType, values, options, writer );
65+
}
66+
writer.endArray();
67+
}
68+
69+
private void visitPluralAggregateValues(
70+
AggregateJdbcType elementJdbcType,
71+
Object values,
72+
WrapperOptions options,
73+
JsonDocumentWriter writer) {
74+
final EmbeddableMappingType embeddableMappingType = elementJdbcType.getEmbeddableMappingType();
75+
if ( values.getClass().isArray() ) {
76+
final var length = Array.getLength( values );
77+
for ( int j = 0; j < length; j++ ) {
78+
try {
79+
visit( embeddableMappingType, Array.get( values, j ), options, writer );
80+
}
81+
catch (IOException e) {
82+
throw new IllegalArgumentException( "Could not serialize array element", e );
83+
}
84+
}
85+
}
86+
else if ( values instanceof Collection<?> collection ) {
87+
for ( final var item : collection ) {
6188
try {
62-
visit( embeddableMappingType, value, options, writer );
89+
visit( embeddableMappingType, item, options, writer );
6390
}
6491
catch (IOException e) {
65-
throw new IllegalArgumentException( "Could not serialize JSON array value", e );
92+
throw new IllegalArgumentException( "Could not serialize array element", e );
6693
}
6794
}
6895
}
6996
else {
70-
assert !(elementJdbcType instanceof AggregateJdbcType);
71-
for ( Object value : values ) {
72-
if ( value == null ) {
97+
throw new IllegalArgumentException(
98+
"Expected array or collection value, but got: " + values.getClass().getName()
99+
);
100+
}
101+
}
102+
103+
private void visitBasicPluralValues(
104+
JavaType<?> elementJavaType,
105+
JdbcType elementJdbcType,
106+
Object values,
107+
WrapperOptions options,
108+
JsonDocumentWriter writer) {
109+
if ( values.getClass().isArray() ) {
110+
final var length = Array.getLength( values );
111+
for ( int j = 0; j < length; j++ ) {
112+
final var item = Array.get( values, j );
113+
if ( item == null ) {
73114
writer.nullValue();
74115
}
75116
else {
76-
writer.serializeJsonValue( value, (JavaType<?>) elementJavaType, elementJdbcType, options );
117+
writer.serializeJsonValue( item, elementJavaType, elementJdbcType, options );
77118
}
78119
}
79120
}
80-
81-
writer.endArray();
82-
}
83-
84-
/**
85-
* Checks that a <code>JDBCType</code> is assignable to an array
86-
*
87-
* @param type the jdbc type
88-
* @return <code>true</code> if types is of array kind <code>false</code> otherwise.
89-
*/
90-
private static boolean isArrayType(JdbcType type) {
91-
return (type.getDefaultSqlTypeCode() == SqlTypes.ARRAY ||
92-
type.getDefaultSqlTypeCode() == SqlTypes.JSON_ARRAY);
121+
else if ( values instanceof Collection<?> collection ) {
122+
for ( final var item : collection ) {
123+
if ( item == null ) {
124+
writer.nullValue();
125+
}
126+
else {
127+
writer.serializeJsonValue( item, elementJavaType, elementJdbcType, options );
128+
}
129+
}
130+
}
131+
else {
132+
throw new IllegalArgumentException(
133+
"Expected array or collection value, but got: " + values.getClass().getName()
134+
);
135+
}
93136
}
94137

95138
public void visit(MappingType mappedType, Object value, WrapperOptions options, JsonDocumentWriter writer)
@@ -106,17 +149,26 @@ else if ( mappedType instanceof ManagedMappingType managedMappingType ) {
106149
serializeObject( managedMappingType, value, options, writer );
107150
}
108151
else if ( mappedType instanceof BasicType<?> basicType ) {
109-
if ( isArrayType( basicType.getJdbcType() ) ) {
110-
final int length = Array.getLength( value );
152+
if ( basicType.getJdbcType() instanceof ArrayJdbcType arrayJdbcType ) {
153+
final var domainValue = basicType.convertToRelationalValue( value );
154+
final var elementJdbcType = arrayJdbcType.getElementJdbcType();
111155
writer.startArray();
112-
if ( length != 0 ) {
113-
//noinspection unchecked
114-
final JavaType<Object> elementJavaType = ((BasicPluralJavaType<Object>) basicType.getJdbcJavaType()).getElementJavaType();
115-
final var elementJdbcType = ((ArrayJdbcType) basicType.getJdbcType()).getElementJdbcType();
116-
final Object domainArray = basicType.convertToRelationalValue( value );
117-
for ( int j = 0; j < length; j++ ) {
118-
writer.serializeJsonValue( Array.get( domainArray, j ), elementJavaType, elementJdbcType, options );
119-
}
156+
if ( elementJdbcType instanceof AggregateJdbcType aggregateJdbcType ) {
157+
visitPluralAggregateValues(
158+
aggregateJdbcType,
159+
domainValue,
160+
options,
161+
writer
162+
);
163+
}
164+
else {
165+
visitBasicPluralValues(
166+
((BasicPluralJavaType<?>) basicType.getJdbcJavaType()).getElementJavaType(),
167+
elementJdbcType,
168+
domainValue,
169+
options,
170+
writer
171+
);
120172
}
121173
writer.endArray();
122174
}

0 commit comments

Comments
 (0)