Jackson JSON: Dynamische Serialisierung

GRudiD

Aktives Mitglied
Hallo,

ich nutze in meinem Projekt die Jackson JSON Bibliothek zum Serialisieren von POJOs. Ich möchte die Serialisierung nun so anpassen, dass nur das Top-Level-Objekt (implements Id) komplett serialisiert wird und alle enthaltenen Objekte, die vom Interface Id erben, nur mit dem Wert id erscheinen. Beispiel:

Java:
interface Id {
	public long getID();
}
	
class A implements Id {
	public String name = "test";
	public B child = new B();
		
	public long getID() {
		return 1;
	}
}
	
class B implements Id {
	public long size = 100;
	
	public long getID() {
		return 2;
	}
}

Die normale Ausgabe als JSON entspricht:
Code:
{
	"id": 1,
	"name": "test",
	"child": {
		"id": 2,
		"size": 100
	}
}

Die gewünschte Ausgabe als JSON sollte aber wie folgt sein:
Code:
{
	"id": 1,
	"name": "test",
	"child": {
		"id": 2
	}
}

Ich habe bereits viel recherchiert aber bisher keine guten Anhaltspunkte gefunden das Problem elegant zu lösen. Der Artikel JacksonSampleCustomViewProcessing - FasterXML Wiki beschreibt im Grunde genommen das gleiche Problem, ist aber mit der aktuellen Version der Bibliothek nicht mehr kompilierbar.

Kennt sich jemand mit der Jackson Bibliothek aus und kann mir ein paar Hinweise liefern? Danke!
 
Zuletzt bearbeitet:

GRudiD

Aktives Mitglied
Einen Schritt weiter bin ich. Mit dem folgenden Filter kann ich die nicht-id Felder, deren Parent nicht Root ist herausfiltern.
Java:
@JsonFilter("myFilter")
class A implements Id {
	...
}

@JsonFilter("myFilter")
class B implements Id {
	...
}

PropertyFilter filter = new SimpleBeanPropertyFilter() {
	@Override
	public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
		if (pojo instanceof Id) {
			if (include(writer)) {
				if (jgen.getOutputContext().getParent().inRoot()) {
					// is root element
					writer.serializeAsField(pojo, jgen, provider);
				} else if ("id".equals(writer.getName()) {
					// is id
					writer.serializeAsField(pojo, jgen, provider);
				} else {
					writer.serializeAsOmittedField(pojo, jgen, provider);
				}
			} else if (!jgen.canOmitFields()) { // since 2.3
				writer.serializeAsOmittedField(pojo, jgen, provider);
			}
		} else {
			writer.serializeAsField(pojo, jgen, provider);
		}
	}

	@Override
	protected boolean include(BeanPropertyWriter writer) {
		return true;
	}

	@Override
	protected boolean include(PropertyWriter writer) {
		return true;
	}
};

FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", filter);
System.out.println(new ObjectMapper().writer(filters).writeValueAsString(a));

Wenn ich ein Id Objekt jetzt allerdings in Arrays verschachtelt in Maps habe, funktioniert das ganze nicht mehr.
 

GRudiD

Aktives Mitglied
Hi,

danke für die Antwort. Leider löst das nicht mein Problem. Beispiel:
Java:
class Node implements Id {
	public long id = 1;
	public String name = "test";
	public Node[] children;
	...
}

Ich möchte erreichen, dass die Klasse Node folgendermaßen dynamisch serialisiert wird:
Code:
{
	"id": 1,
	"name": "test",
	"children": [
		{ "id": 2 },
		{ "id": 3 }
	]
}

Wenn ich nun aber überall ein @JsonIgnore drüberschreibe, würde ich ja immer nur folgendes erhalten:
Code:
{
	"id": 1
}
 

dzim

Top Contributor
Ich dachte du hast unterschiedliche Klassen? In deinem Bsp. von ganz oben musst du doch nur noch in der Klasse B ein @JsonIgnore an die size-Property machen und fertig... Oder hat sich dein Klassenaufbau zu einer Rekursion verändert???
 

GRudiD

Aktives Mitglied
Hi,

mein zweites Beisiel sollte nur verdeutlichen, dass ich nicht einfach ein @JsonIgnore nutzen kann, da ich die Objekte dynamisch zusammenbaue und nicht weiß, welche davon Root und weche davon Child werden. Zudem kann es sein, dass bei einem anderen Aufruf ein Child-Objekt auf einmal Root wird. Trotzdem schonmal danke für deine Hilfe.

Ich hatte die Woche über leider keine Zeit an dem Problem zu arbeiten. Aber vielleicht heute abend :)
 

GRudiD

Aktives Mitglied
Hi,

ich habe jetzt vorerst eine Lösung gefunden. Ich bin mit dieser allerdings noch nicht ganz zufrieden, da ich hiermit mehr oder weniger an jackson vorbeiprogrammiere. Bedeutet z.B. dass ich neue jackson Annotationen erst in meinem Serializer nachprogrammieren muss.

Java:
public class IdSerializer extends StdSerializer<Id> {
	public IdSerializer() {
		super(Id.class);
	}
	
	private void serialize(Id value, JsonGenerator jgen) throws IOException {
		jgen.writeStartObject();
		jgen.writeObjectField("id", value.getId());
		jgen.writeEndObject();
	}

	private void serialize(Collection<?> values, JsonGenerator jgen) throws IOException {
		jgen.writeStartArray();
		for (Object value : values) {
			if (value instanceof Id) {
				this.serialize((Id) value, jgen);
			} else {
				jgen.writeObject(value);
			}
		}
		jgen.writeEndArray();
	}

	private void serialize(Map<?, ?> values, JsonGenerator jgen) throws IOException {
		jgen.writeStartObject();
		for (Object key : values.keySet()) {
			Object value = values.get(key);

			jgen.writeFieldName(String.valueOf(key));
			if (value instanceof Id) {
				this.serialize((Id) value, jgen);
			} else {
				jgen.writeObject(value);
			}
		}
		jgen.writeEndObject();
	}

	@Override
	public void serialize(Id value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
		jgen.writeStartObject();
		for (Field field : value.getClass().getDeclaredFields()) {
			// ignore static fields
			if (Modifier.isStatic(field.getModifiers()))
				continue;
			
			// ignore fields tagged with @JsonIgnore
			JsonIgnore jsonIgnore = field.getAnnotation(JsonIgnore.class);
			if (jsonIgnore != null && jsonIgnore.value())
				continue;
			
			// access private fields
			field.setAccessible(true);
			
			Object obj = null;
			try {
				obj = field.get(value);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
				continue;
			}

			String fieldName = field.getName();
			JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
			if (jsonProperty != null && jsonProperty.value() != null) {
				fieldName = jsonProperty.value();
			}
			jgen.writeFieldName(fieldName);

			if (obj instanceof Id) {
				this.serialize((Id) obj, jgen);
			} else if (field.getType().isArray()) {
				this.serialize(Arrays.asList((Object[]) obj), jgen);
			} else if (Collection.class.isAssignableFrom(field.getType())) {
				this.serialize((Collection<?>) obj, jgen);
			} else if (Map.class.isAssignableFrom(field.getType())) {
				this.serialize((Map<?,?>) obj, jgen);
			} else {
				jgen.writeObject(obj);
			}
		}
		jgen.writeEndObject();
	}
}
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L Jackson JSON: Probleme beim einlesen XML & JSON 1
Joreyk Jackson XML mit interfaces XML & JSON 17
B Klassen mit generischen Attributen mit Jackson lesen XML & JSON 4
S Jackson: Erstellen Sie Klassen für Jackson aus XSD XML & JSON 2
N Deserialisierung mit Jackson XML & JSON 2
B Json Objekt sinnvoll plätten? XML & JSON 1
W com.android.volley.ParseError: org.json.JSONException: End of input at character 0 of XML & JSON 6
L JSON auslesen und Labels in GUI verwenden XML & JSON 13
mananana Frage zu JSON XML & JSON 3
wofus JSON filtern nach bestimmten Wert XML & JSON 7
N JSON export String Unicode? XML & JSON 6
L Json reader XML & JSON 15
megusta JSON umschreiben (converter)? XML & JSON 4
P verschachteltes json verändern XML & JSON 3
Avalon JSON flatten und wieder in DTO konvertieren XML & JSON 21
M Objekt zu jsonArray in .json datei hinzufügen ? XML & JSON 3
Z json inkl. Array/Verschachtelung erstellen XML & JSON 2
J Object in JSON Datei einlesen und als neues Object erzeugen (in ein Object Array) XML & JSON 29
Trèfle Formatierung v. JSON File XML & JSON 7
M json page 2 auslesen XML & JSON 1
K JSON mit GSON nutzen XML & JSON 4
S Java REST Client + Json XML & JSON 8
W Search Value in Json XML & JSON 6
K JSON-Bibliothek XML & JSON 5
M Großes Json Objekt benutzen XML & JSON 5
M Json auslesen XML & JSON 7
M Xml oder Json? XML & JSON 15
J JSON zu Java mit der GSON Google API XML & JSON 0
W Json von URL Lesen (mit Gson Library) XML & JSON 3
W Json von URL Lesen XML & JSON 2
J JSon-Converter gesucht XML & JSON 2
Q Konvertierung von json zum Java Objekt nach vorgegebenem Schema XML & JSON 3
J JSon <-> XML zwecks Validierung XML & JSON 4
M [JSON] Wie Splitten? XML & JSON 14
G Mit JSON Java und C# verbinden XML & JSON 4

Ähnliche Java Themen

Neue Themen


Oben