15 votes

Mapping d'un champ d'objet json dynamique dans Jackson ?

J'ai des objets json dans le schéma suivant :

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

Ici, le payload contient un objet json incorporé, et le schéma de cet objet est dynamique, et différent à chaque fois.

El payload est le résultat brut obtenu à partir de différents services d'API, et de différentes méthodes de différents services d'API. Il n'est pas possible de le faire correspondre à toutes les valeurs possibles.

Est-il possible d'avoir une classe java telle que la suivante :

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

Ou quelque chose de ce genre, afin que je puisse recevoir le schéma de base et le traiter, puis l'envoyer à la classe appropriée qui convertira les données. payload à sa classe attendue appropriée ?

19voto

Cássio Mazzochi Molin Points 11962

Utilisation de JsonNode

Vous pourriez utiliser JsonNode de la com.fasterxml.jackson.databind paquet :

public class Event {

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

    // Getters and setters
}

Puis l'analyser en utilisant :

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

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

Cartographie JsonNode à un POJO

Considérez, par exemple, que vous voulez mettre en correspondance le fichier JsonNode à la classe suivante :

public class Payload {

    private String foo;

    // Getters and setters
}

Cela peut être réalisé avec le morceau de code suivant :

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

Considérant un Map<String, Object>

En fonction de vos besoins, vous pouvez utiliser un Map<String, Object> au lieu de JsonNode :

public class Event {

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

    // Getters and setters
}

Si vous devez convertir un Map<String, Object> à un POJO, utilisez :

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

Selon le Jackson documentation le convertValue() est fonctionnellement similaire à la sérialisation d'une valeur donnée en JSON, puis à la liaison des données JSON à une valeur d'un type donné, mais elle devrait être plus efficace puisque la sérialisation complète ne doit pas avoir lieu. Cependant, les mêmes convertisseurs (sérialiseurs et désérialiseurs) seront utilisés comme pour la liaison de données, ce qui signifie que la même configuration de mappeur d'objets fonctionne.

3voto

Hector Points 763

Cela vous aide-t-il ?

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 + "]";
    }

}

Alors cette classe propriétaire

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 + "]";
    }

}

Ensuite, pour tester

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

    }

}

Donne la sortie console de

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X