Skip to content

Commit b83d3b6

Browse files
committed
HHH-19362 JsonHelper improvements to handle more mapping types
- Create new visitor-like classes that handle the serialization logic - Handle entity values, including tracking circular relationships - Handle plural attribute values
1 parent 567d999 commit b83d3b6

12 files changed

+555
-276
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/OracleOsonArrayJdbcType.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,16 @@
1212
import org.hibernate.dialect.type.OracleJsonArrayJdbcType;
1313
import org.hibernate.internal.CoreLogging;
1414
import org.hibernate.internal.CoreMessageLogger;
15-
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
1615
import org.hibernate.type.descriptor.ValueBinder;
1716
import org.hibernate.type.descriptor.ValueExtractor;
1817
import org.hibernate.type.descriptor.WrapperOptions;
1918
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
2019
import org.hibernate.type.descriptor.java.JavaType;
2120
import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
22-
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
2321
import org.hibernate.type.descriptor.jdbc.BasicBinder;
2422
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
2523
import org.hibernate.type.descriptor.jdbc.JdbcType;
2624
import org.hibernate.type.descriptor.jdbc.JsonHelper;
27-
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
2825
import org.hibernate.type.format.OsonDocumentReader;
2926
import org.hibernate.type.format.OsonDocumentWriter;
3027

@@ -78,20 +75,7 @@ private <T> byte[] toOsonStream(T value, JavaType<T> javaType, WrapperOptions op
7875
}
7976
else {
8077
final OsonDocumentWriter writer = new OsonDocumentWriter( generator );
81-
if ( getElementJdbcType() instanceof JsonJdbcType jsonElementJdbcType ) {
82-
final EmbeddableMappingType embeddableMappingType = jsonElementJdbcType.getEmbeddableMappingType();
83-
JsonHelper.serializeArray( embeddableMappingType, domainObjects, options, writer );
84-
}
85-
else {
86-
assert !(getElementJdbcType() instanceof AggregateJdbcType);
87-
JsonHelper.serializeArray(
88-
elementJavaType,
89-
getElementJdbcType(),
90-
domainObjects,
91-
options,
92-
writer
93-
);
94-
}
78+
JSON_VISITOR.visitArray( elementJavaType, getElementJdbcType(), domainObjects, options, writer );
9579
}
9680
}
9781
return out.toByteArray();

hibernate-core/src/main/java/org/hibernate/dialect/OracleOsonJdbcType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private <T> byte[] toOson(T value, JavaType<T> javaType, WrapperOptions options)
7979
if ( getEmbeddableMappingType() != null ) {
8080
// OracleJsonFactory is used and not OracleOsonFactory as Jackson is not involved here
8181
try (OracleJsonGenerator generator = OSON_JSON_FACTORY.createJsonBinaryGenerator( out )) {
82-
JsonHelper.serialize(
82+
JSON_VISITOR.visit(
8383
getEmbeddableMappingType(),
8484
value,
8585
options,

hibernate-core/src/main/java/org/hibernate/dialect/type/AbstractPostgreSQLStructJdbcType.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import org.hibernate.type.descriptor.jdbc.StructuredJdbcType;
4444
import org.hibernate.type.spi.TypeConfiguration;
4545

46-
import static org.hibernate.type.descriptor.jdbc.StructHelper.getEmbeddedPart;
46+
import static org.hibernate.type.descriptor.jdbc.StructHelper.getSubPart;
4747
import static org.hibernate.type.descriptor.jdbc.StructHelper.instantiate;
4848
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
4949
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
@@ -999,7 +999,7 @@ private SelectableMapping getJdbcValueSelectable(int jdbcValueSelectableIndex) {
999999
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
10001000
int count = 0;
10011001
for ( int i = 0; i < size; i++ ) {
1002-
final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, orderMapping[i] );
1002+
final ValuedModelPart modelPart = getSubPart( embeddableMappingType, orderMapping[i] );
10031003
if ( modelPart.getMappedType() instanceof EmbeddableMappingType embeddableMappingType ) {
10041004
final SelectableMapping aggregateMapping = embeddableMappingType.getAggregateMapping();
10051005
if ( aggregateMapping == null ) {
@@ -1378,7 +1378,7 @@ private StructAttributeValues getAttributeValues(
13781378
attributeIndex = orderMapping[i];
13791379
}
13801380
jdbcIndex += injectAttributeValue(
1381-
getEmbeddedPart( embeddableMappingType, attributeIndex ),
1381+
getSubPart( embeddableMappingType, attributeIndex ),
13821382
attributeValues,
13831383
attributeIndex,
13841384
rawJdbcValues,

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
import java.sql.ResultSet;
1010
import java.sql.SQLException;
1111

12-
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
1312
import org.hibernate.type.SqlTypes;
1413
import org.hibernate.type.descriptor.ValueBinder;
1514
import org.hibernate.type.descriptor.ValueExtractor;
1615
import org.hibernate.type.descriptor.WrapperOptions;
1716
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
1817
import org.hibernate.type.descriptor.java.JavaType;
1918
import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType;
19+
import org.hibernate.type.descriptor.jdbc.spi.JsonGeneratingVisitor;
2020
import org.hibernate.type.format.StringJsonDocumentWriter;
2121

2222
/**
@@ -26,6 +26,8 @@
2626
*/
2727
public class JsonArrayJdbcType extends ArrayJdbcType {
2828

29+
protected static final JsonGeneratingVisitor JSON_VISITOR = new JsonGeneratingVisitor();
30+
2931
public JsonArrayJdbcType(JdbcType elementJdbcType) {
3032
super( elementJdbcType );
3133
}
@@ -74,17 +76,9 @@ protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions opti
7476
return options.getJsonFormatMapper().toString( value, javaType, options);
7577
}
7678
else {
77-
final JdbcType elementJdbcType = getElementJdbcType();
7879
final Object[] domainObjects = javaType.unwrap( value, Object[].class, options );
7980
final StringJsonDocumentWriter writer = new StringJsonDocumentWriter();
80-
if ( elementJdbcType instanceof JsonJdbcType jsonElementJdbcType ) {
81-
final EmbeddableMappingType embeddableMappingType = jsonElementJdbcType.getEmbeddableMappingType();
82-
JsonHelper.serializeArray( embeddableMappingType, domainObjects, options, writer );
83-
}
84-
else {
85-
assert !(elementJdbcType instanceof AggregateJdbcType);
86-
JsonHelper.serializeArray( elementJavaType, elementJdbcType, domainObjects, options, writer );
87-
}
81+
JSON_VISITOR.visitArray( elementJavaType, getElementJdbcType(), domainObjects, options, writer );
8882
return writer.getJson();
8983
}
9084
}

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

Lines changed: 2 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
package org.hibernate.type.descriptor.jdbc;
66

77

8-
import java.io.IOException;
9-
import java.lang.reflect.Array;
108
import java.sql.SQLException;
119
import java.util.AbstractCollection;
1210
import java.util.ArrayList;
@@ -24,20 +22,14 @@
2422
import org.hibernate.internal.util.collections.StandardStack;
2523
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
2624
import org.hibernate.metamodel.mapping.JdbcMapping;
27-
import org.hibernate.metamodel.mapping.MappingType;
2825
import org.hibernate.metamodel.mapping.SelectableMapping;
29-
import org.hibernate.metamodel.mapping.ValuedModelPart;
30-
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
3126
import org.hibernate.type.BasicPluralType;
32-
import org.hibernate.type.BasicType;
33-
import org.hibernate.type.SqlTypes;
3427
import org.hibernate.type.descriptor.WrapperOptions;
3528
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
3629
import org.hibernate.type.descriptor.java.JavaType;
3730
import org.hibernate.type.format.JsonDocumentItemType;
3831
import org.hibernate.type.format.JsonDocumentReader;
39-
import org.hibernate.type.format.JsonDocumentWriter;
40-
import static org.hibernate.type.descriptor.jdbc.StructHelper.getEmbeddedPart;
32+
4133
import static org.hibernate.type.descriptor.jdbc.StructHelper.instantiate;
4234
import org.hibernate.type.format.JsonValueJDBCTypeAdapter;
4335
import org.hibernate.type.format.JsonValueJDBCTypeAdapterFactory;
@@ -52,182 +44,14 @@
5244
@Internal
5345
public class JsonHelper {
5446

55-
/**
56-
* Serializes an array of values into JSON object/array
57-
* @param elementMappingType the type definitions
58-
* @param values the values to be serialized
59-
* @param options wrapping options
60-
* @param writer the document writer used for serialization
61-
*/
62-
public static void serializeArray(MappingType elementMappingType, Object[] values, WrapperOptions options, JsonDocumentWriter writer) {
63-
writer.startArray();
64-
if ( values.length == 0 ) {
65-
writer.endArray();
66-
return;
67-
}
68-
for ( Object value : values ) {
69-
try {
70-
serialize(elementMappingType, value, options, writer);
71-
}
72-
catch (IOException e) {
73-
throw new IllegalArgumentException( "Could not serialize JSON array value" , e );
74-
}
75-
}
76-
writer.endArray();
77-
}
78-
79-
/**
80-
* Serializes an array of values into JSON object/array
81-
* @param elementJavaType the array element type
82-
* @param elementJdbcType the JDBC type
83-
* @param values values to be serialized
84-
* @param options wrapping options
85-
* @param writer the document writer used for serialization
86-
*/
87-
public static void serializeArray(JavaType<?> elementJavaType, JdbcType elementJdbcType, Object[] values, WrapperOptions options, JsonDocumentWriter writer) {
88-
writer.startArray();
89-
if ( values.length == 0 ) {
90-
writer.endArray();
91-
return;
92-
}
93-
for ( Object value : values ) {
94-
if (value == null) {
95-
writer.nullValue();
96-
}
97-
else {
98-
writer.serializeJsonValue( value ,(JavaType<?>) elementJavaType,elementJdbcType,options);
99-
}
100-
}
101-
writer.endArray();
102-
}
103-
104-
/**
105-
* Checks that a <code>JDBCType</code> is assignable to an array
106-
* @param type the jdbc type
107-
* @return <code>true</code> if types is of array kind <code>false</code> otherwise.
108-
*/
109-
private static boolean isArrayType(JdbcType type) {
110-
return (type.getDefaultSqlTypeCode() == SqlTypes.ARRAY ||
111-
type.getDefaultSqlTypeCode() == SqlTypes.JSON_ARRAY);
112-
}
113-
114-
/**
115-
* Serialized an Object value to JSON object using a document writer.
116-
*
117-
* @param embeddableMappingType the embeddable mapping definition of the given value.
118-
* @param domainValue the value to be serialized.
119-
* @param options wrapping options
120-
* @param writer the document writer
121-
* @throws IOException if the underlying writer failed to serialize a mpped value or failed to perform need I/O.
122-
*/
123-
public static void serialize(EmbeddableMappingType embeddableMappingType,
124-
Object domainValue, WrapperOptions options, JsonDocumentWriter writer) throws IOException {
125-
writer.startObject();
126-
serializeMapping(embeddableMappingType, domainValue, options, writer);
127-
writer.endObject();
128-
}
129-
130-
private static void serialize(MappingType mappedType, Object value, WrapperOptions options, JsonDocumentWriter writer)
131-
throws IOException {
132-
if ( value == null ) {
133-
writer.nullValue();
134-
}
135-
else if ( mappedType instanceof EmbeddableMappingType ) {
136-
serialize( (EmbeddableMappingType) mappedType, value, options, writer );
137-
}
138-
else if ( mappedType instanceof BasicType<?> basicType) {
139-
if ( isArrayType(basicType.getJdbcType())) {
140-
final int length = Array.getLength( value );
141-
writer.startArray();
142-
if ( length != 0 ) {
143-
final JavaType<Object> elementJavaType = ( (BasicPluralJavaType<Object>) basicType.getJdbcJavaType() ).getElementJavaType();
144-
final JdbcType elementJdbcType = ( (ArrayJdbcType) basicType.getJdbcType() ).getElementJdbcType();
145-
final Object domainArray = basicType.convertToRelationalValue( value );
146-
for ( int j = 0; j < length; j++ ) {
147-
writer.serializeJsonValue(Array.get(domainArray,j), elementJavaType, elementJdbcType, options);
148-
}
149-
}
150-
writer.endArray();
151-
}
152-
else {
153-
writer.serializeJsonValue(basicType.convertToRelationalValue( value),
154-
(JavaType<Object>)basicType.getJdbcJavaType(),basicType.getJdbcType(), options);
155-
}
156-
}
157-
else {
158-
throw new UnsupportedOperationException( "Support for mapping type not yet implemented: " + mappedType.getClass().getName() );
159-
}
160-
}
161-
162-
/**
163-
* JSON object attirbute serialization
164-
* @see #serialize(EmbeddableMappingType, Object, WrapperOptions, JsonDocumentWriter)
165-
* @param embeddableMappingType the embeddable mapping definition of the given value.
166-
* @param domainValue the value to be serialized.
167-
* @param options wrapping options
168-
* @param writer the document writer
169-
* @throws IOException if an error occurred while writing to an underlying writer
170-
*/
171-
private static void serializeMapping(EmbeddableMappingType embeddableMappingType,
172-
Object domainValue, WrapperOptions options, JsonDocumentWriter writer) throws IOException {
173-
final Object[] values = embeddableMappingType.getValues( domainValue );
174-
for ( int i = 0; i < values.length; i++ ) {
175-
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
176-
if ( attributeMapping instanceof SelectableMapping ) {
177-
final String name = ( (SelectableMapping) attributeMapping ).getSelectableName();
178-
writer.objectKey( name );
179-
180-
if ( attributeMapping.getMappedType() instanceof EmbeddableMappingType ) {
181-
writer.startObject();
182-
serializeMapping( (EmbeddableMappingType)attributeMapping.getMappedType(), values[i], options,writer);
183-
writer.endObject();
184-
}
185-
else {
186-
serialize(attributeMapping.getMappedType(), values[i], options, writer);
187-
}
188-
189-
}
190-
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
191-
if ( values[i] == null ) {
192-
continue;
193-
}
194-
final EmbeddableMappingType mappingType = (EmbeddableMappingType) attributeMapping.getMappedType();
195-
final SelectableMapping aggregateMapping = mappingType.getAggregateMapping();
196-
if (aggregateMapping == null) {
197-
serializeMapping(
198-
mappingType,
199-
values[i],
200-
options,
201-
writer );
202-
}
203-
else {
204-
final String name = aggregateMapping.getSelectableName();
205-
writer.objectKey( name );
206-
writer.startObject();
207-
serializeMapping(
208-
mappingType,
209-
values[i],
210-
options,
211-
writer);
212-
writer.endObject();
213-
214-
}
215-
}
216-
else {
217-
throw new UnsupportedOperationException( "Support for attribute mapping type not yet implemented: " + attributeMapping.getClass().getName() );
218-
}
219-
220-
}
221-
}
222-
22347
/**
22448
* Consumes Json document items from a document reader and return the serialized Objects
22549
* @param reader the document reader
22650
* @param embeddableMappingType the type definitions
22751
* @param returnEmbeddable do we return an Embeddable object or array of Objects ?
22852
* @param options wrapping options
22953
* @return serialized values
230-
* @param <X>
54+
* @param <X> the type of the returned value
23155
* @throws SQLException if error occured during mapping of types
23256
*/
23357
private static <X> X consumeJsonDocumentItems(JsonDocumentReader reader, EmbeddableMappingType embeddableMappingType, boolean returnEmbeddable, WrapperOptions options)

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.hibernate.type.descriptor.ValueExtractor;
1818
import org.hibernate.type.descriptor.WrapperOptions;
1919
import org.hibernate.type.descriptor.java.JavaType;
20+
import org.hibernate.type.descriptor.jdbc.spi.JsonGeneratingVisitor;
2021
import org.hibernate.type.format.StringJsonDocumentReader;
2122
import org.hibernate.type.format.StringJsonDocumentWriter;
2223

@@ -32,6 +33,8 @@ public class JsonJdbcType implements AggregateJdbcType {
3233
*/
3334
public static final JsonJdbcType INSTANCE = new JsonJdbcType( null );
3435

36+
protected static final JsonGeneratingVisitor JSON_VISITOR = new JsonGeneratingVisitor();
37+
3538
private final EmbeddableMappingType embeddableMappingType;
3639

3740
protected JsonJdbcType(EmbeddableMappingType embeddableMappingType) {
@@ -92,7 +95,7 @@ public Object createJdbcValue(Object domainValue, WrapperOptions options) throws
9295
assert embeddableMappingType != null;
9396
final StringJsonDocumentWriter writer = new StringJsonDocumentWriter();
9497
try {
95-
JsonHelper.serialize( embeddableMappingType, domainValue, options, writer );
98+
JSON_VISITOR.visit( embeddableMappingType, domainValue, options, writer );
9699
return writer.getJson();
97100
}
98101
catch (IOException e) {
@@ -110,7 +113,7 @@ protected <X> String toString(X value, JavaType<X> javaType, WrapperOptions opti
110113
if ( embeddableMappingType != null ) {
111114
try {
112115
final StringJsonDocumentWriter writer = new StringJsonDocumentWriter();
113-
JsonHelper.serialize( embeddableMappingType, value, options, writer );
116+
JSON_VISITOR.visit( embeddableMappingType, value, options, writer );
114117
return writer.getJson();
115118
}
116119
catch (IOException e) {

0 commit comments

Comments
 (0)