Jackson /在通用地图中序列化日期到字符串日期 [英] Jackson De/Serializing Date-to-String-to-Date in generic Maps

查看:156
本文介绍了Jackson /在通用地图中序列化日期到字符串日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有很多杰克逊来自/来自java.util.Date代码的例子,但是他们似乎都在利用POJO注释。我有一个通用的标量地图,我想去/序列化到JSON。这是当前的解串器设置;非常简单:

There are many examples of Jackson to/from java.util.Date code but they all seem to leverage POJO annotation. I have generic Maps of scalars that I wish to de/serialize to JSON. This is the current deserializer setup; very simple:

public class JSONUtils {
    static {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

        mapper = new ObjectMapper();

        mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
        mapper.setDateFormat(df);  // this works for outbounds but has no effect on inbounds

        mapper.getDeserializationConfig().with(df); // Gave this a shot but still does not sniff strings for a format that we declare should be treated as java.util.Date                           
  }
  public static Map<String,Object> parseJSON(InputStream is) {
    Map<String,Object> data = null;

    try {
        data = mapper.readValue(is, Map.class);
    } catch(Exception e) {
      // ...
    }

    return data;
}

我发现一个日期记录器可以将java.util.Date转换为ISO 8601 -ish字符串。这是另一种困惑我的方式。显然,在没有上下文的JSON文档中,字符串是一个字符串,所以我不知道它是否是一个日期。所以我准备鸭子打这个,并检查所有被反序列化的字符串,如果它们闻起来像YYYY-MM-DDTHH:MM:SS.sss datetimes,那么我将使一个java.util.Date而不是传回一个String。所以给出:

I grok that a dateserializer can turn java.util.Date into a ISO 8601-ish string. It's going the other way that puzzles me. Clearly, in a JSON doc with no context, a string is a string so I cannot know if it was once a date. So I am prepared to duck type this and examine all strings being deserialized and if they smell like YYYY-MM-DDTHH:MM:SS.sss datetimes, then I will make a java.util.Date instead of just passing back a String. So given:

{ "name": "buzz",
  "theDate": "2013-09-10T12:00:00.000"
}

将产生

Map<String,Object> m = mapper.readValue(is, Map.class);
Object o1 = m.get("name");   // o1 is instanceof String
Object o2 = m.get("theDate");  // o2 is instanceof Date

但这意味着解串器必须返回两种不同的类型,在杰克逊没有能力找出如何做到这一点。有谁知道一个好的,紧凑的例子,将嗅到类似日期的字符串,并将其变成日期,将其他字符串作为字符串?

But this means that the deserializer has to return two different types and I have not been able to figure out how to do this in Jackson. Does anyone know of a good, compact example that will sniff for date-like strings and turn them into Dates, leaving others as Strings?

推荐答案

如果您有一个 POJO ,您可以使用序列化程序和解串器的get和set方法轻松使用注释。

If you have a POJO, you can easy use annotation on get and set method with serializer and deserializer.

以不同的方式序列化和反序列化对象:列表< POJO> String String 地图地图列表< POJO> 再次。显然,在地图中, Date 的值是 String

following an example that serialize and deserialize objects in different ways: List<POJO> to String, String to Map and Map to List<POJO> again. Obviously, in the map the Date values are as String.

此解决方案是线程安全的,因为使用 org.joda.time.format.DateTimeFormat org.joda.time.format.DateTimeFormatter 可以找到更多信息这篇文章杰克逊日期反序列化和此链接 http://fahdshariff.blogspot.co.uk/2010/08/dateformat-with-multiple-threads.html

This solution is thread safe because uses org.joda.time.format.DateTimeFormat and org.joda.time.format.DateTimeFormatter, you can find more info herein this post Jackson date deserialization and this link http://fahdshariff.blogspot.co.uk/2010/08/dateformat-with-multiple-threads.html

我的POJO:

@JsonAutoDetect
public class QueueTask implements Serializable {

    private static final long serialVersionUID = -4411796657106403937L;

    public enum ActivitiQueueStatus {

        IN_PROGRESS(AsyncProcessingWorkflowContentModel.InProgressTask.TYPE.getLocalName()), //
        IN_QUEUE(AsyncProcessingWorkflowContentModel.InQueueTask.TYPE.getLocalName());

        private String value;

        private ActivitiQueueStatus(final String value) {
            this.value = value;
        }

        public static ActivitiQueueStatus enumOf(final String value) {
            for (ActivitiQueueStatus enum_i : values()) {
                if (enum_i.value.equals(value))
                    return enum_i;
            }
            throw new IllegalArgumentException("value '" + value + "' is not a valid enum");
        }
    }

    private String user;

    private Date creationDate;

    private int noRowsSelected;

    private ActivitiQueueStatus status;


    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    @JsonSerialize(using = JsonDateSerializer.class)
    public Date getCreationDate() {
        return creationDate;
    }

    @JsonDeserialize(using = JsonDateDeSerializer.class)
    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public int getNoRowsSelected() {
        return noRowsSelected;
    }

    public void setNoRowsSelected(int noRowsSelected) {
        this.noRowsSelected = noRowsSelected;
    }

    public ActivitiQueueStatus getStatus() {
        return status;
    }

    public void setStatus(ActivitiQueueStatus status) {
        this.status = status;
    }

}

我的序列化器:

@Component
public class JsonDateDeSerializer extends JsonDeserializer<Date> {

    // use joda library for thread safe issue
    private static final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm:ss");

    @Override
    public Date deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (jp.getCurrentToken().equals(JsonToken.VALUE_STRING))
            return dateFormat.parseDateTime(jp.getText().toString()).toDate();
        return null;
    }

}

和解串器:

@Component
public class JsonDateSerializer extends JsonSerializer<Date> {

    // use joda library for thread safe issue
    private static final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("dd/MM/yyyy hh:mm:ss");

    @Override
    public void serialize(final Date date, final JsonGenerator gen, final SerializerProvider provider) throws IOException, JsonProcessingException {

        final String formattedDate = dateFormat.print(date.getTime());

        gen.writeString(formattedDate);
    }

}

我的服务:

public class ServiceMock {

    // mock this parameter for usage.
    public List<QueueTask> getActiveActivities(QName taskStatus) {
        final List<QueueTask> listToReturn = new LinkedList<QueueTask>();

        final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
        Date d1 = null, d2 = null, d3 = null, d4 = null, d5 = null;

        try {
            d1 = dateFormat.parse("01/02/2013 12:44:44");
            d2 = dateFormat.parse("21/12/2013 16:44:44");
            d3 = dateFormat.parse("21/12/2013 16:45:44");
            d4 = dateFormat.parse("21/12/2013 16:44:46");
            d5 = dateFormat.parse("11/09/2013 16:44:44");
        } catch (ParseException e) {
        }

        QueueTask dataSet = new QueueTask();
        dataSet = new QueueTask();
        dataSet.setUser("user_b");
        dataSet.setStatus(ActivitiQueueStatus.enumOf("placeInQueue"));
        dataSet.setNoRowsSelected(500);
        dataSet.setCreationDate(d1);
        listToReturn.add(dataSet);

        dataSet = new QueueTask();
        dataSet.setUser("user_d");
        dataSet.setStatus(ActivitiQueueStatus.enumOf("placeInQueue"));
        dataSet.setNoRowsSelected(300);
        dataSet.setCreationDate(d2);
        listToReturn.add(dataSet);

        dataSet = new QueueTask();
        dataSet.setUser("user_a");
        dataSet.setStatus(ActivitiQueueStatus.enumOf("inProgress"));
        dataSet.setNoRowsSelected(700);
        dataSet.setCreationDate(d3);
        listToReturn.add(dataSet);

        dataSet = new QueueTask();
        dataSet.setUser("user_k");
        dataSet.setStatus(ActivitiQueueStatus.enumOf("inProgress"));
        dataSet.setNoRowsSelected(700);
        dataSet.setCreationDate(d4);
        listToReturn.add(dataSet);

        dataSet = new QueueTask();
        dataSet.setUser("user_l");
        dataSet.setStatus(ActivitiQueueStatus.enumOf("inProgress"));
        dataSet.setNoRowsSelected(700);
        dataSet.setCreationDate(d5);
        listToReturn.add(dataSet);

        return listToReturn;
    }

}

主要用法:

public class SerializationServiceTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(OUPQueueStatusServiceIT.class);

    public void testGetActiveActivitiesSerialization() throws Exception {
        LOGGER.info("testGetActiveActivitiesSerialization - start");

        ServiceMock mockedService = new ServiceMock();

        // AsyncProcessingWorkflowContentModel.InProgressTask.TYPE is an QName, mock this calling
        List<QueueTask> tasks = mockedService.getActiveActivities(AsyncProcessingWorkflowContentModel.InProgressTask.TYPE);
        assertNotNull(tasks);
        assertTrue(tasks.size() == 5);
        assertNotNull(tasks.get(0).getUser());
        assertNotNull(tasks.get(0).getCreationDate());
        assertNotNull(tasks.get(0).getStatus());
        assertNotNull(tasks.get(0).getNoRowsSelected());

        final ObjectMapper mapper = new ObjectMapper();
        final String jsonString = mapper.writeValueAsString(tasks);

        assertNotNull(jsonString);
        assertTrue(jsonString.contains("creationDate"));

        // test serialization from string to Map
        final List<Map<String, Object>> listOfMap = mapper.readValue(jsonString, new TypeReference<List<Map<String, Object>>>() {
        });
        assertNotNull(listOfMap);

        final DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
        for (Map<String, Object> map_i : listOfMap) {
            // check date value
            assertTrue(map_i.containsKey("creationDate"));
            final Date date = formatter.parse("" + map_i.get("creationDate"));
            assertNotNull(date);

            assertNotNull(map_i.get("user"));
            assertNotNull(map_i.get("status"));
            assertNotNull(ActivitiQueueStatus.valueOf("" + map_i.get("status")));
            assertNotNull(map_i.get("noRowsSelected"));
        }

        // test de-serialization
        List<QueueTask> deserializedTaskList = mapper.convertValue(listOfMap, new TypeReference<List<QueueTask>>() {
        });

        assertNotNull(deserializedTaskList);
        assertTrue(deserializedTaskList.size() == 5);
        for (QueueTask t : deserializedTaskList) {
            assertNotNull(t.getUser());
            assertNotNull(t.getCreationDate());
            assertNotNull(t.getDownloadType());
            assertNotNull(t.getStatus());
        }
        LOGGER.info("testGetActiveActivitiesSerialization - end");
    }

    public static void main(String[] args) throws Exception {
        new SerializationServiceTest().SerializationServiceTest();
    }

}

这篇关于Jackson /在通用地图中序列化日期到字符串日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆