Jackson De /在一般地图中序列化日期到字符串的日期

Buz*_*tti 9 java json date jackson deserialization

杰克逊有很多来自java.util.Date代码的例子,但他们似乎都在利用POJO注释.我有通用的标量映射,我希望将其/序列化为JSON.这是当前的解串器设置; 非常简单:

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;
}
Run Code Online (Sandbox Code Playgroud)

我知道dateserializer可以将java.util.Date转换为ISO 8601-ish字符串.这是困扰我的另一种方式.显然,在没有上下文的JSON文档中,字符串是一个字符串,所以我不知道它是否曾经是一个日期.所以我准备对这种类型进行处理并检查所有被反序列化的字符串,如果它们闻起来像YYYY-MM-DDTHH:MM:SS.sss日期时间,那么我将创建一个java.util.Date而不是仅仅传回一个String.所以给出:

{ "name": "buzz",
  "theDate": "2013-09-10T12:00:00.000"
}
Run Code Online (Sandbox Code Playgroud)

会屈服

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
Run Code Online (Sandbox Code Playgroud)

但这意味着解串器必须返回两种不同的类型,我无法弄清楚如何在杰克逊中做到这一点.有没有人知道一个好的,紧凑的例子,它将嗅到类似日期的字符串并将它们变成日期,将其他人留作字符串?

Giu*_*ldo 5

如果您有POJO,则可以通过序列化器和反序列化器在get和set方法上轻松使用批注。

下面的一个例子是,在不同的方式进行序列化和反序列化对象:List<POJO>StringStringMap,并MapList<POJO>一次。显然,在地图中,Date值是String

此解决方案是线程安全的,因为使用org.joda.time.format.DateTimeFormatorg.joda.time.format.DateTimeFormatter,您可以在本文中找到更多信息。如何使用Jackson来反序列化JS日期?和此链接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;
    }

}
Run Code Online (Sandbox Code Playgroud)

我的序列化器:

@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;
    }

}
Run Code Online (Sandbox Code Playgroud)

和反序列化器:

@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的服务:

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

主要用法:

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();
    }

}
Run Code Online (Sandbox Code Playgroud)


小智 5

我最近一直在寻找相关主题的答案,并提出了以下解决方案,这要感谢Justin Musgrove和他的文章Custom jackson date deserializer。基本上,这个想法是替换 Object.class 的标准反序列化器,它会将指定格式的任何字符串转换为 Date 对象,否则回退到标准行为。显然,此操作需要额外处理,因此您需要为此配置一个专用的 ObjectMapper 实例,并且仅在绝对必要或准备进行第二遍时才使用它。

请注意,您示例中的日期字符串格式没有时区组件,这可能会导致一些问题,但我按要求保留了格式。您可以使用您选择的解析器代替来自Apache Commons Lang的 FastDateFormat 。在我的情况下,我实际上使用 Instant 。

CustomObjectDeserializer.java

import java.io.IOException;

import org.apache.commons.lang3.time.FastDateFormat;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;

public class CustomObjectDeserializer extends UntypedObjectDeserializer {
    private static final long serialVersionUID = 1L;

    private static final FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS");

    public CustomObjectDeserializer() {
        super(null, null);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (p.getCurrentTokenId() == JsonTokenId.ID_STRING) {
            try {
                String value = p.getText();
                // put your own parser here
                return format.parse(value);
            } catch (Exception e) {
                return super.deserialize(p, ctxt);
            }
        } else {
            return super.deserialize(p, ctxt);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

JSONUtils.java

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class JSONUtils {
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);

        SimpleModule module = new SimpleModule("DateConverter");
        // register a new deserializer extending and replacing UntypedObjectDeserializer 
        module.addDeserializer(Object.class, new CustomObjectDeserializer());
        mapper.registerModule(module);
    }

    public static Map<String, Object> parseJSON(InputStream is) {
        Map<String, Object> data = null;

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

        return data;
    }

    public static void main(String[] args) throws Exception {
        String input = "{\"name\": \"buzz\", \"theDate\": \"2013-09-10T12:00:00.000\"}";
        InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));

        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
        System.out.println(o1.getClass().getName() + " : " + o1);
        System.out.println(o2.getClass().getName() + " : " + o2);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 -1

下面是一个关于如何使用 Jackson 对对象中的日期进行序列化和反序列化的基本示例

公共类 JacksonSetup {

private static class JacksonSerializer {

    private static JacksonSerializer instance;

    private JacksonSerializer() {

    }

    public static JacksonSerializer getInstance() {
        if (instance == null)
            instance = new JacksonSerializer();
        return instance;
    }

    public <E extends ModelObject> void writeTo(E object, Class<E> type, OutputStream out) throws IOException {
        ObjectMapper mapper = getMapper();
        mapper.writeValue(out, object);
    }

    public <E extends ModelObject> void writeTo(E object, Class<E> type, Writer out) throws IOException {
        ObjectMapper mapper = getMapper();
        mapper.writeValue(out, object);
    }

    public <E extends ModelObject> E read(String input, Class<E> type) throws IOException {
        ObjectMapper mapper = getMapper();
        E result = (E) mapper.readValue(input, type);
        return result;
    }

    private ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
        mapper.setAnnotationIntrospector(introspector);
        return mapper;
    }

}

private static class JaxbDateSerializer extends XmlAdapter<String, Date> {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");

    @Override
    public String marshal(Date date) throws Exception {
        return dateFormat.format(date);
    }

    @Override
    public Date unmarshal(String date) throws Exception {
        return dateFormat.parse(date);
    }
}

private static abstract class ModelObject {

}

private static class Person extends ModelObject {

    private String name;

    private Date bday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlElement(name = "birth-day")
    @XmlJavaTypeAdapter(JaxbDateSerializer.class)
    public Date getBday() {
        return bday;
    }

    public void setBday(Date bday) {
        this.bday = bday;
    }
}

public static void main(String[] args) {
    try {
        Person person = new Person();
        person.setName("Jhon Doe");
        person.setBday(new Date());

        Writer writer = new StringWriter();
        JacksonSerializer.getInstance().writeTo(person, Person.class, writer);
        System.out.println(writer.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

}