将对象序列化为以对象 class 为键的映射?

Serialize objects to a map with the object class as the key?

我正在编写一个应用程序,使用 Spring boot 和 jackson 进行 JSON 解析。我需要像这样处理另一个产生 JSON 的服务:

{
  "task-id": 5081,
  "task-created-on": {
    "java.util.Date": 1631022026000
  }
}

值得注意的是,某些字段(例如此处的日期字段)被序列化为具有单个键值对的映射,其中键是 java classname,值是实际值领域的。

我一直在浏览 jackson 文档,但没有找到任何关于这种格式的信息。有没有办法配置 jackson 来生成和解析这种格式的字段?

至少,我需要处理这种格式的日期。但我相信该服务也将这种格式用于其他对象,其中映射键将是任意 java class 的名称,而值将是它自己的映射。因此,如果可能的话,我会对处理的不仅仅是日期的解决方案感兴趣。

可以通过以下步骤在 Jackson 中使用 自定义序列化程序 轻松完成。
首先,创建序列化对象如下:

class MyDateObject {
    private Date date;

    //general getter/setter
}

class Task {
    @JsonProperty("task-id")
    private int taskId;

    @JsonProperty("task-created-on")
    private MyDateObject taskCreatedOn;

    //general getters/setters
}

其次,定义您的自定义序列化程序:(请注意,我使用 myDateObject.getDate().getClass().getName() 获取日期字段的 class 名称。)

class DateSerializer extends StdSerializer<MyDateObject> {
    public DateSerializer() {
        this(null);
    }

    protected DateSerializer(Class<MyDateObject> t) {
        super(t);
    }

    @Override
    public void serialize(MyDateObject myDateObject, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeNumberField(myDateObject.getDate().getClass().getName(), myDateObject.getDate().getTime());
        jsonGenerator.writeEndObject();
    }
}

最后,用ObjectMapperMyDateObjectclass注册序列化器并执行序列化:

MyDateObject myDateObject = new MyDateObject();
myDateObject.setDate(new Date());

Task task = new Task();
task.setTaskId(5081);
task.setTaskCreatedOn(myDateObject);

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(MyDateObject.class, new DateSerializer());

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(simpleModule);

System.out.println(objectMapper.writeValueAsString(task));

预期输出为:

{"task-id":5081,"task-created-on":{"java.util.Date":1633402076254}}


详情请参考Jackson – Custom Serializer

可以通过对您感兴趣的 pojo 中的字段使用自定义 JsonSerializer and applying the JsonSerialize 来解决问题,如下所示:

public class Task {

    @JsonProperty("task-id")
    private int taskId;

    @JsonProperty("task-created-on")
    @JsonSerialize(using = ObjectSerializer.class)
    Date taskCreatedOn; 
}

自定义序列化程序将使用 JsonGenerator.html#writeObjectField 将通用对象(Date 或其他 java class)序列化为 propertyname : {"class名称”:值}:

public class ObjectSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(Object t, JsonGenerator jg, SerializerProvider sp) throws IOException {
        jg.writeStartObject();
        jg.writeObjectField(t.getClass().getName(), t);
        jg.writeEndObject();
    }

}