6
6
*/
7
7
package org .hibernate .type .format .jackson ;
8
8
9
- import org .hibernate .type .format .FormatMapper ;
9
+ import java .io .IOException ;
10
+ import java .lang .reflect .Type ;
11
+ import java .util .ArrayList ;
12
+
10
13
import org .hibernate .type .descriptor .WrapperOptions ;
11
14
import org .hibernate .type .descriptor .java .JavaType ;
15
+ import org .hibernate .type .format .FormatMapper ;
12
16
17
+ import com .fasterxml .jackson .core .JsonParser ;
13
18
import com .fasterxml .jackson .core .JsonProcessingException ;
19
+ import com .fasterxml .jackson .core .JsonToken ;
20
+ import com .fasterxml .jackson .databind .DeserializationContext ;
21
+ import com .fasterxml .jackson .databind .JsonDeserializer ;
14
22
import com .fasterxml .jackson .databind .ObjectMapper ;
23
+ import com .fasterxml .jackson .databind .SerializationFeature ;
24
+ import com .fasterxml .jackson .databind .module .SimpleModule ;
15
25
import com .fasterxml .jackson .dataformat .xml .XmlMapper ;
26
+ import com .fasterxml .jackson .dataformat .xml .ser .ToXmlGenerator ;
16
27
17
28
/**
18
29
* @author Christian Beikov
@@ -24,20 +35,37 @@ public final class JacksonXmlFormatMapper implements FormatMapper {
24
35
private final ObjectMapper objectMapper ;
25
36
26
37
public JacksonXmlFormatMapper () {
27
- this (new XmlMapper () );
38
+ this ( createXmlMapper () );
28
39
}
29
40
30
41
public JacksonXmlFormatMapper (ObjectMapper objectMapper ) {
31
42
this .objectMapper = objectMapper ;
32
43
}
33
44
45
+ private static XmlMapper createXmlMapper () {
46
+ final XmlMapper xmlMapper = new XmlMapper ();
47
+ // needed to automatically find and register Jackson's jsr310 module for java.time support
48
+ xmlMapper .findAndRegisterModules ();
49
+ xmlMapper .configure ( SerializationFeature .WRITE_DATES_AS_TIMESTAMPS , false );
50
+ xmlMapper .enable ( ToXmlGenerator .Feature .WRITE_NULLS_AS_XSI_NIL );
51
+ // Workaround for null vs empty string handling inside arrays,
52
+ // see: https://github.com/FasterXML/jackson-dataformat-xml/issues/344
53
+ final SimpleModule module = new SimpleModule ();
54
+ module .addDeserializer ( String [].class , new StringArrayDeserializer () );
55
+ xmlMapper .registerModule ( module );
56
+ return xmlMapper ;
57
+ }
58
+
34
59
@ Override
35
60
public <T > T fromString (CharSequence charSequence , JavaType <T > javaType , WrapperOptions wrapperOptions ) {
36
61
if ( javaType .getJavaType () == String .class || javaType .getJavaType () == Object .class ) {
37
62
return (T ) charSequence .toString ();
38
63
}
39
64
try {
40
- return objectMapper .readValue ( charSequence .toString (), objectMapper .constructType ( javaType .getJavaType () ) );
65
+ return objectMapper .readValue (
66
+ charSequence .toString (),
67
+ objectMapper .constructType ( javaType .getJavaType () )
68
+ );
41
69
}
42
70
catch (JsonProcessingException e ) {
43
71
throw new IllegalArgumentException ( "Could not deserialize string to java type: " + javaType , e );
@@ -49,12 +77,35 @@ public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapper
49
77
if ( javaType .getJavaType () == String .class || javaType .getJavaType () == Object .class ) {
50
78
return (String ) value ;
51
79
}
80
+ else if ( javaType .getJavaTypeClass ().isArray () ) {
81
+ if ( javaType .getJavaTypeClass ().getComponentType ().isEnum () ) {
82
+ // for enum arrays we need to explicitly pass Byte[] as the writer type
83
+ return writeValueAsString ( value , javaType , Byte [].class );
84
+ }
85
+ }
86
+ return writeValueAsString ( value , javaType , javaType .getJavaType () );
87
+ }
88
+
89
+ private <T > String writeValueAsString (Object value , JavaType <T > javaType , Type type ) {
52
90
try {
53
- return objectMapper .writerFor ( objectMapper .constructType ( javaType .getJavaType () ) )
54
- .writeValueAsString ( value );
91
+ return objectMapper .writerFor ( objectMapper .constructType ( type ) ).writeValueAsString ( value );
55
92
}
56
93
catch (JsonProcessingException e ) {
57
94
throw new IllegalArgumentException ( "Could not serialize object of java type: " + javaType , e );
58
95
}
59
96
}
97
+
98
+ private static class StringArrayDeserializer extends JsonDeserializer <String []> {
99
+ @ Override
100
+ public String [] deserialize (JsonParser jp , DeserializationContext deserializationContext ) throws IOException {
101
+ final ArrayList <String > result = new ArrayList <>();
102
+ JsonToken token ;
103
+ while ( ( token = jp .nextValue () ) != JsonToken .END_OBJECT ) {
104
+ if ( token .isScalarValue () ) {
105
+ result .add ( jp .getValueAsString () );
106
+ }
107
+ }
108
+ return result .toArray ( String []::new );
109
+ }
110
+ }
60
111
}
0 commit comments