1616package org .springframework .data .redis .hash ;
1717
1818import java .io .IOException ;
19+ import java .text .ParseException ;
1920import java .util .ArrayList ;
21+ import java .util .Date ;
2022import java .util .HashMap ;
2123import java .util .Iterator ;
2224import java .util .LinkedHashMap ;
2931import org .springframework .data .mapping .MappingException ;
3032import org .springframework .data .util .DirectFieldAccessFallbackBeanWrapper ;
3133import org .springframework .util .Assert ;
34+ import org .springframework .util .NumberUtils ;
3235import org .springframework .util .StringUtils ;
3336
3437import com .fasterxml .jackson .annotation .JsonInclude .Include ;
3538import com .fasterxml .jackson .annotation .JsonTypeInfo .As ;
39+ import com .fasterxml .jackson .core .JsonParser ;
40+ import com .fasterxml .jackson .databind .BeanDescription ;
41+ import com .fasterxml .jackson .databind .DeserializationConfig ;
42+ import com .fasterxml .jackson .databind .DeserializationContext ;
3643import com .fasterxml .jackson .databind .DeserializationFeature ;
44+ import com .fasterxml .jackson .databind .JavaType ;
45+ import com .fasterxml .jackson .databind .JsonDeserializer ;
3746import com .fasterxml .jackson .databind .JsonNode ;
3847import com .fasterxml .jackson .databind .ObjectMapper ;
3948import com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping ;
4049import com .fasterxml .jackson .databind .SerializationFeature ;
50+ import com .fasterxml .jackson .databind .deser .BeanDeserializerModifier ;
51+ import com .fasterxml .jackson .databind .deser .DeserializationProblemHandler ;
52+ import com .fasterxml .jackson .databind .deser .std .UntypedObjectDeserializer ;
53+ import com .fasterxml .jackson .databind .jsontype .TypeIdResolver ;
54+ import com .fasterxml .jackson .databind .module .SimpleModule ;
55+ import com .fasterxml .jackson .databind .type .TypeFactory ;
4156
4257/**
4358 * {@link ObjectMapper} based {@link HashMapper} implementation that allows flattening. Given an entity {@code Person}
6580 *
6681 * <strong>Normal</strong>
6782 * <table>
68- * <tr><th>Hash field</th><th>Value<th></tr>
69- * <tr><td>firstname</td><td>Jon<td></tr>
70- * <tr><td>lastname</td><td>Snow<td></tr>
71- * <tr><td>address</td><td>{ "city" : "Castle Black", "country" : "The North" }<td></tr>
83+ * <tr>
84+ * <th>Hash field</th>
85+ * <th>Value
86+ * <th>
87+ * </tr>
88+ * <tr>
89+ * <td>firstname</td>
90+ * <td>Jon
91+ * <td>
92+ * </tr>
93+ * <tr>
94+ * <td>lastname</td>
95+ * <td>Snow
96+ * <td>
97+ * </tr>
98+ * <tr>
99+ * <td>address</td>
100+ * <td>{ "city" : "Castle Black", "country" : "The North" }
101+ * <td>
102+ * </tr>
72103 * </table>
73104 * <br />
74105 * <strong>Flat</strong>:
75106 * <table>
76- * <tr><th>Hash field</th><th>Value<th></tr>
77- * <tr><td>firstname</td><td>Jon<td></tr>
78- * <tr><td>lastname</td><td>Snow<td></tr>
79- * <tr><td>address.city</td><td>Castle Black<td></tr>
80- * <tr><td>address.country</td><td>The North<td></tr>
107+ * <tr>
108+ * <th>Hash field</th>
109+ * <th>Value
110+ * <th>
111+ * </tr>
112+ *
113+ * <tr>
114+ * <td>firstname</td>
115+ * <td>Jon
116+ * <td>
117+ * </tr>
118+ * <tr>
119+ * <td>lastname</td>
120+ * <td>Snow
121+ * <td>
122+ * </tr>
123+ * <tr>
124+ * <td>address.city</td>
125+ * <td>Castle Black
126+ * <td>
127+ * </tr>
128+ * <tr>
129+ * <td>address.country</td>
130+ * <td>The North
131+ * <td>
132+ * </tr>
81133 * </table>
82134 *
83135 * @author Christoph Strobl
@@ -103,6 +155,50 @@ public Jackson2HashMapper(boolean flatten) {
103155typingMapper .configure (SerializationFeature .WRITE_NULL_MAP_VALUES , false );
104156typingMapper .setSerializationInclusion (Include .NON_NULL );
105157typingMapper .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
158+
159+ typingMapper .addHandler (new DeserializationProblemHandler () {
160+ @ Override
161+ public JavaType handleMissingTypeId (DeserializationContext ctxt , JavaType baseType , TypeIdResolver idResolver ,
162+ String failureMsg ) {
163+ return TypeFactory .defaultInstance ().constructSimpleType (java .util .Date .class , new JavaType [] {});
164+ }
165+ });
166+
167+ SimpleModule module = new SimpleModule ();
168+ module .setDeserializerModifier (new BeanDeserializerModifier () {
169+ @ Override
170+ public JsonDeserializer <?> modifyDeserializer (DeserializationConfig config , BeanDescription beanDesc ,
171+ JsonDeserializer <?> deserializer ) {
172+
173+ if (beanDesc .getBeanClass ().equals (java .util .Date .class )) {
174+ return new JsonDeserializer <Object >() {
175+
176+ JsonDeserializer <?> delegate = new UntypedObjectDeserializer (null , null );
177+
178+ @ Override
179+ public Object deserialize (JsonParser p , DeserializationContext ctxt ) throws IOException {
180+
181+ Object val = delegate .deserialize (p , ctxt );
182+
183+ if (val instanceof Date ) {
184+ return val ;
185+ }
186+
187+ try {
188+ return ctxt .getConfig ().getDateFormat ().parse (val .toString ());
189+ } catch (ParseException e ) {
190+ e .printStackTrace ();
191+ return new Date (NumberUtils .parseNumber (val .toString (), Long .class ));
192+ }
193+ }
194+ };
195+ }
196+
197+ return deserializer ;
198+ }
199+ });
200+
201+ typingMapper .registerModule (module );
106202}
107203
108204/**
@@ -242,6 +338,7 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
242338}
243339
244340JsonNode element = (JsonNode ) source ;
341+
245342if (element .isArray ()) {
246343
247344Iterator <JsonNode > nodes = element .elements ();
@@ -250,7 +347,13 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
250347
251348JsonNode cur = nodes .next ();
252349if (cur .isArray ()) {
253- this .falttenCollection (propertyPrefix , cur .elements (), resultMap );
350+ this .flattenCollection (propertyPrefix , cur .elements (), resultMap );
351+ } else {
352+
353+ if (cur .asText ().equals ("java.util.Date" )) {
354+ resultMap .put (propertyPrefix , nodes .next ().asText ());
355+ break ;
356+ }
254357}
255358}
256359
@@ -261,7 +364,7 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
261364}
262365}
263366
264- private void falttenCollection (String propertyPrefix , Iterator <JsonNode > list , Map <String , Object > resultMap ) {
367+ private void flattenCollection (String propertyPrefix , Iterator <JsonNode > list , Map <String , Object > resultMap ) {
265368
266369int counter = 0 ;
267370while (list .hasNext ()) {
0 commit comments