如何使用Jackson和MongoDB传递JSON消息中的属性?

lex*_*ore 10 java spring json jackson microservices

我们有一个微服务,它从队列中获取一些JSON数据,稍微处理它并再次通过队列发送处理结果.在微服务中,我们不JSONObject直接使用喜欢的东西,我们使用Jackson将JSON映射到Java类.

处理时,微服务只对传入消息的某些属性感兴趣,而不是所有属性.想象一下它刚收到

{
    "operand1": 3,
    "operand2": 5,
    /* other properties may come here */
}
Run Code Online (Sandbox Code Playgroud)

并发送:

{
    "operand1": 3,
    "operand2": 5,
    "multiplicationResult": 15,
    /* other properties may come here */
}
Run Code Online (Sandbox Code Playgroud)

如果没有在我的类中明确映射它们,我如何隧道传递或传递我对此服务不感兴趣的消息的其他属性?

出于这种微服务的目的,它具有如下结构就足够了:

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我没有映射所有其他属性,它们将丢失.

如果我确实映射它们,那么每次消息结构发生变化时,我都必须更新这个微服务的模型,这需要付出努力并且容易出错.

Gre*_*y.K 5

最简单的方法是在敏捷结构的情况下使用Map而不是自定义POJO:

它很容易从JSON中读取,例如使用JsonParser parser(这里的 java文档):

Map<String, Object> fields =
      parser.readValueAs(new TypeReference<Map<String, Object>>() {});
Run Code Online (Sandbox Code Playgroud)

使用BasicDBObject(这里的 java文档)很容易写入MongoDB :

DBCollection collection = db.getCollection("tasks");
collection.insert(new BasicDBObject(fields));
Run Code Online (Sandbox Code Playgroud)

你甚至可以通过包装实现它Map具有Task这样的:

public class Task {
    private final Map<String, Object> fields;

    public final double operand1;
    // And so on...

    @JsonCreator
    public Task(Map<String, Object> fields) {
        this.fields = fields;

        this.operand1 = 0; /* Extract desired values from the Map */
    }

    @JsonValue
    public Map<String, Object> toMap() {
        return this.fields;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果需要,也可以使用自定义JsonDeserializer(在这种情况下Task必须注释@JsonDeserialize(using = TaskDeserializer.class)):

public class TaskDeserializer extends JsonDeserializer<Task> {
    @Override
    public Task deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        Map<String, Object> fields = parser.readValueAs(new TypeReference<Map<String, Object>>() {});
        return new Task(fields);
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ott 2

这些都不是很好,但是您可以做的是将结构分成两部分 - 一个由微服务反序列化的结构化部分,以及一个包含其他 JSON 的单独的“additionalFields”字段,然后您可以修改 JSON这个字段里面没有改变Task。您可以将嵌套 JSON 添加为String.

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
   public String additionalFields
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以添加一个Map<String, Object>,它允许您添加键值对,但同样,您会失去类型安全性:

public class Task {
   public double operand1;
   public double operand2;
   public double multiplicationResult;
   public Map<String, Object> additionalFields
}
Run Code Online (Sandbox Code Playgroud)