diff --git a/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java b/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java index 97f637aa3..84ea4414b 100644 --- a/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java @@ -16,7 +16,9 @@ package org.springframework.data.redis.hash; import java.io.IOException; +import java.text.ParseException; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; @@ -29,15 +31,28 @@ import java.util.Set; import org.springframework.data.mapping.MappingException; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; import org.springframework.util.Assert; +import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; +import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; +import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.TypeFactory; /** * {@link ObjectMapper} based {@link HashMapper} implementation that allows flattening. Given an entity {@code Person} @@ -65,19 +80,56 @@ import com.fasterxml.jackson.databind.SerializationFeature; * * Normal * - * - * - * - * + * + * + * + * + * + * + * + * + * + * + * + * *
Hash fieldValue
firstnameJon
lastnameSnow
address{ "city" : "Castle Black", "country" : "The North" }
Hash fieldValue + * + *
firstnameJon + * + *
lastnameSnow + * + *
address{ "city" : "Castle Black", "country" : "The North" } + * + *
*
* Flat: * - * - *   - * - * - * + * + * + * + *   + * + * + * + * + * + * + * + * + * + * + * + * *
Hash fieldValue
firstnameJon
lastnameSnow
address.cityCastle Black
address.countryThe North
Hash fieldValue + * + *
firstnameJon + * + *
lastnameSnow + * + *
address.cityCastle Black + * + *
address.countryThe North + * + *
* * @author Christoph Strobl @@ -103,6 +155,50 @@ public class Jackson2HashMapper implements HashMapper { typingMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); typingMapper.setSerializationInclusion(Include.NON_NULL); typingMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + typingMapper.addHandler(new DeserializationProblemHandler() { + @Override + public JavaType handleMissingTypeId(DeserializationContext ctxt, JavaType baseType, TypeIdResolver idResolver, + String failureMsg) { + return TypeFactory.defaultInstance().constructSimpleType(java.util.Date.class, new JavaType[] {}); + } + }); + + SimpleModule module = new SimpleModule(); + module.setDeserializerModifier(new BeanDeserializerModifier() { + @Override + public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, + JsonDeserializer deserializer) { + + if (beanDesc.getBeanClass().equals(java.util.Date.class)) { + return new JsonDeserializer() { + + JsonDeserializer delegate = new UntypedObjectDeserializer(null, null); + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + + Object val = delegate.deserialize(p, ctxt); + + if (val instanceof Date) { + return val; + } + + try { + return ctxt.getConfig().getDateFormat().parse(val.toString()); + } catch (ParseException e) { + e.printStackTrace(); + return new Date(NumberUtils.parseNumber(val.toString(), Long.class)); + } + } + }; + } + + return deserializer; + } + }); + + typingMapper.registerModule(module); } /** @@ -242,6 +338,7 @@ public class Jackson2HashMapper implements HashMapper { } JsonNode element = (JsonNode) source; + if (element.isArray()) { Iterator nodes = element.elements(); @@ -250,7 +347,13 @@ public class Jackson2HashMapper implements HashMapper { JsonNode cur = nodes.next(); if (cur.isArray()) { - this.falttenCollection(propertyPrefix, cur.elements(), resultMap); + this.flattenCollection(propertyPrefix, cur.elements(), resultMap); + } else { + + if (cur.asText().equals("java.util.Date")) { + resultMap.put(propertyPrefix, nodes.next().asText()); + break; + } } } @@ -261,7 +364,7 @@ public class Jackson2HashMapper implements HashMapper { } } - private void falttenCollection(String propertyPrefix, Iterator list, Map resultMap) { + private void flattenCollection(String propertyPrefix, Iterator list, Map resultMap) { int counter = 0; while (list.hasNext()) { diff --git a/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperTests.java b/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperTests.java index d1f74a827..90885ae1f 100644 --- a/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperTests.java +++ b/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperTests.java @@ -97,5 +97,4 @@ public class Jackson2HashMapperTests { Person result = (Person) mapper.fromHash(template. opsForHash().entries("JON-SNOW")); Assert.assertThat(result, Is.is(jon)); } - } diff --git a/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperUnitTests.java b/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperUnitTests.java index d0d6fd8aa..6c7da8772 100644 --- a/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperUnitTests.java +++ b/src/test/java/org/springframework/data/redis/mapping/Jackson2HashMapperUnitTests.java @@ -20,6 +20,7 @@ import lombok.Data; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -161,6 +162,16 @@ public class Jackson2HashMapperUnitTests extends AbstractHashMapperTest { assertBackAndForwardMapping(outer); } + @Test // DATAREDIS-1001 + public void dateValueShouldBeTreatedCorrectly() { + + WithDate source = new WithDate(); + source.string = "id-1"; + source.date = new Date(1561543964015L); + + assertBackAndForwardMapping(source); + } + @Data public static class WithList { List strings; @@ -174,4 +185,11 @@ public class Jackson2HashMapperUnitTests extends AbstractHashMapperTest { Map objects; Map persons; } + + @Data + static class WithDate { + + private String string; + private Date date; + } }