Mapping a dynamic json object field in Jackson?

后端 未结 2 1289
野的像风
野的像风 2020-12-03 07:58

I have json objects in the following schema:

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

Here, th

相关标签:
2条回答
  • 2020-12-03 08:18

    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}]]
    
    0 讨论(0)
  • 2020-12-03 08:22

    Using JsonNode

    You could use JsonNode from the com.fasterxml.jackson.databind package:

    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

    Consider, for example, you want to map the JsonNode instance to the following class:

    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>

    Depending on your requirements, you could use a Map<String, Object> instead of 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:

    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. However, same converters (serializers and deserializers) will be used as for data binding, meaning same object mapper configuration works.

    0 讨论(0)
提交回复
热议问题