J'ai des objets json dans le schéma suivant:
{
name: "foo",
timestamp: 1475840608763,
payload:
{
foo: "bar"
}
}
Ici, le champ payload
contient un objet json incorporé, et le schéma de cet objet est dynamique et différent à chaque fois.
L'objet payload
est la sortie brute obtenue à partir de différents services API et de différentes méthodes de différents services API. Il n'est pas possible de le mapper à 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 dans ce sens, afin que je puisse recevoir le schéma de base et le traiter, puis l'envoyer à la classe appropriée qui convertira payload
en sa classe attendue appropriée?
JsonNode
Vous pouvez utiliser JsonNode
à partir du package com.fasterxml.jackson.databind
:
public class Event {
public String name;
public long timestamp;
public JsonNode payload;
// Getters and setters
}
Ensuite, analysez-le en utilisant:
String json = "{\"name\":\"foo\",\"timestamp\":1475840608763,"
+ "\"payload\":{\"foo\":\"bar\"}}";
ObjectMapper mapper = new ObjectMapper();
Event event = mapper.readValue(json, Event.class);
JsonNode
à un POJOConsidérez, par exemple, que vous souhaitez mapper l'instance JsonNode
à la classe suivante:
public class Payload {
private String foo;
// Getters and setters
}
Cela peut être réalisé avec le code suivant:
Payload payload = mapper.treeToValue(event.getPayload(), Payload.class);
Map<String, Object>
Selon 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>
En POJO, utilisez:
Payload payload = mapper.convertValue(event.getPayload(), Payload.class);
Selon Jackson documentation , la méthode convertValue()
est fonctionnellement similaire à la première sérialisation de la valeur donnée en JSON, puis à la liaison des données JSON en valeur de type donné, mais devrait être plus efficace car la sérialisation complète ne se produit pas (doit). Cependant, les mêmes convertisseurs (sérialiseurs et désérialiseurs) seront utilisés que pour la liaison de données, ce qui signifie que la même configuration de mappeur d'objets fonctionne.
Est-ce que cela aide?
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 + "]";
}
}
Ensuite, 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}]]