简体   繁体   English

在Jackson中映射动态json对象字段?

[英]Mapping a dynamic json object field in Jackson?

I have json objects in the following schema: 我在以下架构中有json对象:

{
  name: "foo",
  timestamp: 1475840608763,
  payload:
  {
     foo: "bar"
  }
}

Here, the payload field contains an embedded json object, and the schema of this object is dynamic, and different each time. 这里, payload字段包含一个嵌入的json对象,该对象的模式是动态的,每次都不同。

The payload object is the raw output obtained from different API services, and different methods of different API services. payload对象是从不同API服务获得的原始输出,以及不同API服务的不同方法。 It isn't possible to map it to all possible values. 无法将其映射到所有可能的值。

Is it possible to have a java class such as the following: 是否可以拥有一个java类,如下所示:

public class Event
{
    public String name;
    public long timestamp;
    public JsonObject payload;
}

Or something along those lines, so I can receive the basic schema and process it, then send it to the relevant class which will convert payload to its appropriate expected class? 或者沿着这些方向的东西,所以我可以接收基本模式并处理它,然后将它发送到相关的类,它将payload转换为适当的预期类?

Using JsonNode 使用JsonNode

You could use JsonNode from the com.fasterxml.jackson.databind package: 你可以使用JsonNodecom.fasterxml.jackson.databind包:

public class Event {

    public String name;
    public long timestamp;
    public JsonNode payload;

    // Getters and setters
}

Then parse it using: 然后使用以下方法解析它:

String json = "{\"name\":\"foo\",\"timestamp\":1475840608763,"
            + "\"payload\":{\"foo\":\"bar\"}}";

ObjectMapper mapper = new ObjectMapper();
Event event = mapper.readValue(json, Event.class);

Mapping JsonNode to a POJO JsonNode映射到POJO

Consider, for example, you want to map the JsonNode instance to the following class: 例如,考虑您要将JsonNode实例映射到以下类:

public class Payload {

    private String foo;

    // Getters and setters
}

It can be achieved with the following piece of code: 它可以通过以下代码实现:

Payload payload = mapper.treeToValue(event.getPayload(), Payload.class);

Considering a Map<String, Object> 考虑Map<String, Object>

Depending on your requirements, you could use a Map<String, Object> instead of JsonNode : 根据您的要求,您可以使用Map<String, Object>而不是JsonNode

public class Event {

    public String name;
    public long timestamp;
    public Map<String, Object> payload;

    // Getters and setters
}

If you need to convert a Map<String, Object> to a POJO, use: 如果需要将Map<String, Object>转换为POJO,请使用:

Payload payload = mapper.convertValue(event.getPayload(), Payload.class);

According to the Jackson documentation , the convertValue() method is functionally similar to first serializing given value into JSON, and then binding JSON data into value of given type, but should be more efficient since full serialization does not (need to) occur. 根据Jackson 文档convertValue()方法在功能上类似于首先将给定值序列化为JSON,然后将JSON数据绑定到给定类型的值,但应该更高效,因为完全序列化不会(需要)发生。 However, same converters (serializers and deserializers) will be used as for data binding, meaning same object mapper configuration works. 但是,相同的转换器(序列化器和反序列化器)将用于数据绑定,这意味着相同的对象映射器配置工作。

Does this help? 这有帮助吗?

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;

public class Payload {

    private final Map<String, Object> other = new HashMap<>();

    @JsonAnyGetter
    public Map<String, Object> any() {
        return other;
    }

    @JsonAnySetter
    public void set(final String name, final Object value) {
        other.put(name, value);
    }

    public Map<String, Object> getOther() {
        return other;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = (prime * result) + ((other == null) ? 0 : other.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Payload)) {
            return false;
        }
        Payload other = (Payload) obj;
        if (this.other == null) {
            if (other.other != null) {
                return false;
            }
        } else if (!this.other.equals(other.other)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Payload [other=" + other + "]";
    }

}

Then this owning class 然后是这个拥有的班级

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Outer {

    private final String name;
    private final long timestamp;

    private final Payload payload;

    @JsonCreator
    public Outer(@JsonProperty("name") final String name, @JsonProperty("timestamp") final long timestamp, @JsonProperty("payload") final Payload payload) {
        super();
        this.name = name;
        this.timestamp = timestamp;
        this.payload = payload;
    }

    public String getName() {
        return name;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public Payload getPayload() {
        return payload;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
        result = (prime * result) + ((payload == null) ? 0 : payload.hashCode());
        result = (prime * result) + (int) (timestamp ^ (timestamp >>> 32));
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Outer)) {
            return false;
        }
        Outer other = (Outer) obj;
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        if (payload == null) {
            if (other.payload != null) {
                return false;
            }
        } else if (!payload.equals(other.payload)) {
            return false;
        }
        if (timestamp != other.timestamp) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Outer [name=" + name + ", timestamp=" + timestamp + ", payload=" + payload + "]";
    }

}

Then to test 然后去测试

public class Main {

    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(final String... args) throws JsonParseException, JsonMappingException, IOException {

        final Outer outer = mapper.readValue(new File("test.json"), Outer.class);

        System.out.println(outer);


    }

}

Gives console output of 提供控制台输出

Outer [name=foo, timestamp=1475840608763, payload=Payload [other={foo=bar}]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM