15
15
*/
16
16
package org .springframework .data .redis .hash ;
17
17
18
- import static com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping .* ;
18
+ import static com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping .EVERYTHING ;
19
19
20
20
import java .io .IOException ;
21
21
import java .text .ParseException ;
22
22
import java .util .ArrayList ;
23
+ import java .util .Arrays ;
23
24
import java .util .Calendar ;
25
+ import java .util .Collections ;
24
26
import java .util .Date ;
25
27
import java .util .HashMap ;
26
28
import java .util .Iterator ;
32
34
import java .util .Set ;
33
35
34
36
import org .springframework .data .mapping .MappingException ;
37
+ import org .springframework .data .redis .support .collections .CollectionUtils ;
35
38
import org .springframework .data .util .DirectFieldAccessFallbackBeanWrapper ;
39
+ import org .springframework .lang .NonNull ;
40
+ import org .springframework .lang .Nullable ;
36
41
import org .springframework .util .Assert ;
37
42
import org .springframework .util .ClassUtils ;
38
43
import org .springframework .util .NumberUtils ;
39
- import org .springframework .util .ObjectUtils ;
40
44
import org .springframework .util .StringUtils ;
41
45
42
46
import com .fasterxml .jackson .annotation .JsonInclude .Include ;
@@ -233,8 +237,12 @@ public Object fromHash(Map<String, Object> hash) {
233
237
234
238
if (flatten ) {
235
239
236
- return typingMapper .reader ().forType (Object .class )
237
- .readValue (untypedMapper .writeValueAsBytes (doUnflatten (hash )));
240
+ Map <String , Object > unflattenedHash = doUnflatten (hash );
241
+ byte [] unflattenedHashedBytes = untypedMapper .writeValueAsBytes (unflattenedHash );
242
+ Object hashedObject = typingMapper .reader ().forType (Object .class )
243
+ .readValue (unflattenedHashedBytes );;
244
+
245
+ return hashedObject ;
238
246
}
239
247
240
248
return typingMapper .treeToValue (untypedMapper .valueToTree (hash ), Object .class );
@@ -248,31 +256,37 @@ public Object fromHash(Map<String, Object> hash) {
248
256
private Map <String , Object > doUnflatten (Map <String , Object > source ) {
249
257
250
258
Map <String , Object > result = new LinkedHashMap <>();
251
- Set <String > treatSeperate = new LinkedHashSet <>();
259
+ Set <String > treatSeparate = new LinkedHashSet <>();
260
+
252
261
for (Entry <String , Object > entry : source .entrySet ()) {
253
262
254
263
String key = entry .getKey ();
255
- String [] args = key .split ("\\ ." );
264
+ String [] keyParts = key .split ("\\ ." );
256
265
257
- if (args .length == 1 && ! args [0 ]. contains ( "[" )) {
266
+ if (keyParts .length == 1 && isNotIndexed ( keyParts [0 ])) {
258
267
result .put (entry .getKey (), entry .getValue ());
259
268
continue ;
260
269
}
261
270
262
- if (args .length == 1 && args [0 ]. contains ( "[" )) {
271
+ if (keyParts .length == 1 && isIndexed ( keyParts [0 ])) {
263
272
264
- String prunedKey = args [0 ].substring (0 , args [0 ].indexOf ('[' ));
265
- if (result .containsKey (prunedKey )) {
266
- appendValueToTypedList (args [0 ], entry .getValue (), (List <Object >) result .get (prunedKey ));
267
- } else {
268
- result .put (prunedKey , createTypedListWithValue (entry .getValue ()));
273
+ String indexedKeyName = keyParts [0 ];
274
+ String nonIndexedKeyName = stripIndex (indexedKeyName );
275
+
276
+ int index = getIndex (indexedKeyName );
277
+
278
+ if (result .containsKey (nonIndexedKeyName )) {
279
+ addValueToTypedListAtIndex ((List <Object >) result .get (nonIndexedKeyName ), index , entry .getValue ());
280
+ }
281
+ else {
282
+ result .put (nonIndexedKeyName , createTypedListWithValue (index , entry .getValue ()));
269
283
}
270
284
} else {
271
- treatSeperate .add (key .substring (0 , key .indexOf ('.' )));
285
+ treatSeparate .add (key .substring (0 , key .indexOf ('.' )));
272
286
}
273
287
}
274
288
275
- for (String partial : treatSeperate ) {
289
+ for (String partial : treatSeparate ) {
276
290
277
291
Map <String , Object > newSource = new LinkedHashMap <>();
278
292
@@ -284,12 +298,13 @@ private Map<String, Object> doUnflatten(Map<String, Object> source) {
284
298
285
299
if (partial .endsWith ("]" )) {
286
300
287
- String prunedKey = partial .substring (0 , partial .indexOf ('[' ));
301
+ String nonIndexPartial = stripIndex (partial );
302
+ int index = getIndex (partial );
288
303
289
- if (result .containsKey (prunedKey )) {
290
- appendValueToTypedList ( partial , doUnflatten ( newSource ), ( List <Object >) result .get (prunedKey ));
304
+ if (result .containsKey (nonIndexPartial )) {
305
+ addValueToTypedListAtIndex (( List <Object >) result .get (nonIndexPartial ), index , doUnflatten ( newSource ));
291
306
} else {
292
- result .put (prunedKey , createTypedListWithValue (doUnflatten (newSource )));
307
+ result .put (nonIndexPartial , createTypedListWithValue (index , doUnflatten (newSource )));
293
308
}
294
309
} else {
295
310
result .put (partial , doUnflatten (newSource ));
@@ -299,6 +314,27 @@ private Map<String, Object> doUnflatten(Map<String, Object> source) {
299
314
return result ;
300
315
}
301
316
317
+ private boolean isIndexed (@ NonNull String value ) {
318
+ return value .indexOf ('[' ) > -1 ;
319
+ }
320
+
321
+ private boolean isNotIndexed (@ NonNull String value ) {
322
+ return !isIndexed (value );
323
+ }
324
+
325
+ private int getIndex (@ NonNull String indexedValue ) {
326
+ return Integer .parseInt (indexedValue .substring (indexedValue .indexOf ('[' ) + 1 , indexedValue .length () - 1 ));
327
+ }
328
+
329
+ private @ NonNull String stripIndex (@ NonNull String indexedValue ) {
330
+
331
+ int indexOfLeftBracket = indexedValue .indexOf ("[" );
332
+
333
+ return indexOfLeftBracket > -1
334
+ ? indexedValue .substring (0 , indexOfLeftBracket )
335
+ : indexedValue ;
336
+ }
337
+
302
338
private Map <String , Object > flattenMap (Iterator <Entry <String , JsonNode >> source ) {
303
339
304
340
Map <String , Object > resultMap = new HashMap <>();
@@ -314,7 +350,6 @@ private void doFlatten(String propertyPrefix, Iterator<Entry<String, JsonNode>>
314
350
}
315
351
316
352
while (inputMap .hasNext ()) {
317
-
318
353
Entry <String , JsonNode > entry = inputMap .next ();
319
354
flattenElement (propertyPrefix + entry .getKey (), entry .getValue (), resultMap );
320
355
}
@@ -323,7 +358,6 @@ private void doFlatten(String propertyPrefix, Iterator<Entry<String, JsonNode>>
323
358
private void flattenElement (String propertyPrefix , Object source , Map <String , Object > resultMap ) {
324
359
325
360
if (!(source instanceof JsonNode )) {
326
-
327
361
resultMap .put (propertyPrefix , source );
328
362
return ;
329
363
}
@@ -337,6 +371,7 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
337
371
while (nodes .hasNext ()) {
338
372
339
373
JsonNode cur = nodes .next ();
374
+
340
375
if (cur .isArray ()) {
341
376
this .flattenCollection (propertyPrefix , cur .elements (), resultMap );
342
377
} else {
@@ -370,12 +405,13 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
370
405
371
406
try {
372
407
resultMap .put (propertyPrefix , next .binaryValue ());
373
- } catch (IOException e ) {
374
- throw new IllegalStateException (String .format ("Cannot read binary value of '%s'" , propertyPrefix ), e );
408
+ } catch (IOException cause ) {
409
+ String message = String .format ("Cannot read binary value of '%s'" , propertyPrefix );
410
+ throw new IllegalStateException (message , cause );
375
411
}
412
+
376
413
break ;
377
414
}
378
-
379
415
}
380
416
}
381
417
}
@@ -390,53 +426,49 @@ private void flattenElement(String propertyPrefix, Object source, Map<String, Ob
390
426
private boolean mightBeJavaType (JsonNode node ) {
391
427
392
428
String textValue = node .asText ();
393
- if (!SOURCE_VERSION_PRESENT ) {
394
-
395
- if (ObjectUtils .nullSafeEquals (textValue , "java.util.Date" )) {
396
- return true ;
397
- }
398
- if (ObjectUtils .nullSafeEquals (textValue , "java.math.BigInteger" )) {
399
- return true ;
400
- }
401
- if (ObjectUtils .nullSafeEquals (textValue , "java.math.BigDecimal" )) {
402
- return true ;
403
- }
404
429
405
- return false ;
430
+ if (!SOURCE_VERSION_PRESENT ) {
431
+ return Arrays .asList ("java.util.Date" , "java.math.BigInteger" , "java.math.BigDecimal" ).contains (textValue );
406
432
}
407
- return javax .lang .model .SourceVersion .isName (textValue );
408
433
434
+ return javax .lang .model .SourceVersion .isName (textValue );
409
435
}
410
436
411
437
private void flattenCollection (String propertyPrefix , Iterator <JsonNode > list , Map <String , Object > resultMap ) {
412
438
413
- int counter = 0 ;
414
- while (list .hasNext ()) {
439
+ for (int counter = 0 ; list .hasNext (); counter ++) {
415
440
JsonNode element = list .next ();
416
441
flattenElement (propertyPrefix + "[" + counter + "]" , element , resultMap );
417
- counter ++;
418
442
}
419
443
}
420
444
421
445
@ SuppressWarnings ("unchecked" )
422
- private void appendValueToTypedList ( String key , Object value , List < Object > destination ) {
446
+ private void addValueToTypedListAtIndex ( List < Object > listWithTypeHint , int index , Object value ) {
423
447
424
- int index = Integer .parseInt (key .substring (key .indexOf ('[' ) + 1 , key .length () - 1 ));
425
- List <Object > resultList = ((List <Object >) destination .get (1 ));
426
- if (resultList .size () < index ) {
427
- resultList .add (value );
428
- } else {
429
- resultList .add (index , value );
448
+ List <Object > valueList = (List <Object >) listWithTypeHint .get (1 );
449
+
450
+ if (index >= valueList .size ()) {
451
+ int initialCapacity = index + 1 ;
452
+ List <Object > newValueList = new ArrayList <>(initialCapacity );
453
+ Collections .copy (CollectionUtils .initializeList (newValueList , initialCapacity ), valueList );
454
+ listWithTypeHint .set (1 , newValueList );
455
+ valueList = newValueList ;
430
456
}
457
+
458
+ valueList .set (index , value );
431
459
}
432
460
433
- private List <Object > createTypedListWithValue (Object value ) {
461
+ private List <Object > createTypedListWithValue (int index , Object value ) {
462
+
463
+ int initialCapacity = index + 1 ;
464
+
465
+ List <Object > valueList = CollectionUtils .initializeList (new ArrayList <>(initialCapacity ), initialCapacity );
466
+ valueList .set (index , value );
434
467
435
468
List <Object > listWithTypeHint = new ArrayList <>();
436
- listWithTypeHint .add (ArrayList .class .getName ()); // why jackson? why?
437
- List <Object > values = new ArrayList <>();
438
- values .add (value );
439
- listWithTypeHint .add (values );
469
+ listWithTypeHint .add (ArrayList .class .getName ());
470
+ listWithTypeHint .add (valueList );
471
+
440
472
return listWithTypeHint ;
441
473
}
442
474
@@ -468,16 +500,16 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, Typ
468
500
@ Override
469
501
public Date deserialize (JsonParser p , DeserializationContext ctxt ) throws IOException {
470
502
471
- Object val = delegate .deserialize (p , ctxt );
503
+ Object value = delegate .deserialize (p , ctxt );
472
504
473
- if (val instanceof Date ) {
474
- return (Date ) val ;
505
+ if (value instanceof Date ) {
506
+ return (Date ) value ;
475
507
}
476
508
477
509
try {
478
- return ctxt .getConfig ().getDateFormat ().parse (val .toString ());
479
- } catch (ParseException e ) {
480
- return new Date (NumberUtils .parseNumber (val .toString (), Long .class ));
510
+ return ctxt .getConfig ().getDateFormat ().parse (value .toString ());
511
+ } catch (ParseException cause ) {
512
+ return new Date (NumberUtils .parseNumber (value .toString (), Long .class ));
481
513
}
482
514
}
483
515
}
@@ -500,13 +532,13 @@ public Calendar deserialize(JsonParser p, DeserializationContext ctxt) throws IO
500
532
501
533
Date date = dateDeserializer .deserialize (p , ctxt );
502
534
503
- if (date == null ) {
504
- return null ;
535
+ if (date != null ) {
536
+ Calendar calendar = Calendar .getInstance ();
537
+ calendar .setTime (date );
538
+ return calendar ;
505
539
}
506
540
507
- Calendar calendar = Calendar .getInstance ();
508
- calendar .setTime (date );
509
- return calendar ;
541
+ return null ;
510
542
}
511
543
}
512
544
@@ -524,17 +556,20 @@ private static class UntypedSerializer<T> extends JsonSerializer<T> {
524
556
}
525
557
526
558
@ Override
527
- public void serializeWithType (T value , JsonGenerator gen , SerializerProvider serializers , TypeSerializer typeSer )
528
- throws IOException {
529
- serialize (value , gen , serializers );
559
+ public void serializeWithType (T value , JsonGenerator jsonGenerator , SerializerProvider serializers ,
560
+ TypeSerializer typeSerializer ) throws IOException {
561
+
562
+ serialize (value , jsonGenerator , serializers );
530
563
}
531
564
532
565
@ Override
533
- public void serialize (T value , JsonGenerator gen , SerializerProvider serializers ) throws IOException {
534
- if (value == null ) {
535
- serializers .defaultSerializeNull (gen );
566
+ public void serialize (@ Nullable T value , JsonGenerator jsonGenerator , SerializerProvider serializers )
567
+ throws IOException {
568
+
569
+ if (value != null ) {
570
+ delegate .serialize (value , jsonGenerator , serializers );
536
571
} else {
537
- delegate . serialize ( value , gen , serializers );
572
+ serializers . defaultSerializeNull ( jsonGenerator );
538
573
}
539
574
}
540
575
}
0 commit comments