Ich habe zwei Java-Klassen, die ich mit Jackson in JSON serialisieren möchte:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Item {
public final int id;
public final String itemNr;
public final User createdBy;
public Item(int id, String itemNr, User createdBy) {
this.id = id;
this.itemNr = itemNr;
this.createdBy = createdBy;
}
}
Ich möchte ein Element für diesen JSON serialisieren:
{"id":7, "itemNr":"TEST", "createdBy":3}
mit Benutzer serialisiert, um nur die einzuschließen id
. Ich werde auch in der Lage sein, alle Benutzerobjekte für JSON zu serilisieren, wie:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Ich denke also, dass ich einen benutzerdefinierten Serializer schreiben Item
und damit versuchen muss:
public class ItemSerializer extends JsonSerializer<Item> {
@Override
public void serialize(Item value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.id);
jgen.writeNumberField("itemNr", value.itemNr);
jgen.writeNumberField("createdBy", value.user.id);
jgen.writeEndObject();
}
}
Ich serialisiere den JSON mit diesem Code von Jackson How-to: Custom Serializers :
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule",
new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Aber ich bekomme diesen Fehler:
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
at com.example.JsonTest.main(JsonTest.java:54)
Wie kann ich mit Jackson einen benutzerdefinierten Serializer verwenden?
So würde ich es mit Gson machen:
public class UserAdapter implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.id);
}
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(User.class, new UserAdapter());
Gson gson = builder.create();
String json = gson.toJson(myItem);
System.out.println("JSON: "+json);
Aber ich muss es jetzt mit Jackson machen, da Gson keine Unterstützung für Schnittstellen hat.
java
json
serialization
jackson
Jonas
quelle
quelle
Item
? Ich habe ein Problem, bei dem meine Controller-Methode ein standardisiertes serialisiertes Objekt zurückgibtTypeA
, aber für eine andere bestimmte Controller-Methode möchte ich es anders serialisieren. Wie würde das aussehen?Antworten:
Wie bereits erwähnt, ist @JsonValue ein guter Weg. Wenn Ihnen ein benutzerdefinierter Serializer nichts ausmacht, müssen Sie keinen für Item, sondern einen für User schreiben. Wenn ja, ist dies so einfach wie:
Eine weitere Möglichkeit ist die Implementierung
JsonSerializable
. In diesem Fall ist keine Registrierung erforderlich.Was den Fehler betrifft; Das ist komisch - Sie möchten wahrscheinlich auf eine spätere Version aktualisieren. Es ist jedoch auch sicherer zu erweitern,
org.codehaus.jackson.map.ser.SerializerBase
da es Standardimplementierungen nicht wesentlicher Methoden enthält (dh alles außer dem tatsächlichen Serialisierungsaufruf).quelle
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Sie können
@JsonSerialize(using = CustomDateSerializer.class)
jedes Datumsfeld des zu serialisierenden Objekts überschreiben.quelle
@JsonSerialize(contentUsing= ...)
beim Kommentieren von Sammlungen (z. B.@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Ich habe es auch versucht, und der Beispielcode auf der Jackson-Webseite enthält einen Fehler, der den Typ nicht enthält (
.class
) nicht in den Aufruf deraddSerializer()
Methode einbezieht. Dieser sollte folgendermaßen lauten:Mit anderen Worten, dies sind die Zeilen, die
simpleModule
den Serializer instanziieren und hinzufügen (wobei die vorherige falsche Zeile auskommentiert ist):Zu Ihrer Information: Hier ist die Referenz für den richtigen Beispielcode: http://wiki.fasterxml.com/JacksonFeatureModules
quelle
Verwenden Sie @JsonValue:
@JsonValue funktioniert nur mit Methoden, daher müssen Sie die Methode getId hinzufügen. Sie sollten in der Lage sein, Ihren benutzerdefinierten Serializer vollständig zu überspringen.
quelle
Ich habe ein Beispiel für eine benutzerdefinierte
Timestamp.class
Serialisierung / Deserialisierung geschrieben, aber Sie können es verwenden, was immer Sie wollen.Gehen Sie beim Erstellen des Objekt-Mappers folgendermaßen vor:
Zum Beispiel
java ee
könnten Sie es folgendermaßen initialisieren:wo der Serializer so etwas sein sollte:
und Deserializer so etwas:
quelle
Dies sind Verhaltensmuster, die mir beim Versuch aufgefallen sind, die Jackson-Serialisierung zu verstehen.
1) Angenommen, es gibt ein Objekt Klassenzimmer und eine Klasse Schüler. Ich habe alles öffentlich und endgültig gemacht.
2) Angenommen, dies sind die Serialisierer, die wir zum Serialisieren der Objekte in JSON verwenden. Das writeObjectField verwendet den eigenen Serializer des Objekts, wenn es beim Object Mapper registriert ist. Wenn nicht, wird es als POJO serialisiert. Das writeNumberField akzeptiert ausschließlich nur Grundelemente als Argumente.
3) Registrieren Sie nur einen DoubleSerializer mit DecimalFormat-Ausgabemuster
###,##0.000
in SimpleModule und die Ausgabe lautet:Sie können sehen, dass die POJO-Serialisierung zwischen double und Double unterscheidet, indem Sie den DoubleSerialzer für Doubles und ein reguläres String-Format für Doubles verwenden.
4) Registrieren Sie DoubleSerializer und ClassroomSerializer ohne den StudentSerializer. Wir erwarten, dass die Ausgabe so ist, dass sie sich wie ein Double verhält, wenn wir ein Double als Objekt schreiben, und wenn wir ein Double als Zahl schreiben, verhält es sich wie ein Double. Die Student-Instanzvariable sollte als POJO geschrieben werden und dem obigen Muster folgen, da sie nicht registriert wird.
5) Registrieren Sie alle Serializer. Die Ausgabe ist:
genau wie erwartet.
Ein weiterer wichtiger Hinweis: Wenn Sie mehrere Serializer für dieselbe Klasse mit demselben Modul registriert haben, wählt das Modul den Serializer für die Klasse aus, die zuletzt zur Liste hinzugefügt wurde. Dies sollte nicht verwendet werden - es ist verwirrend und ich bin nicht sicher, wie konsistent dies ist
Moral: Wenn Sie die Serialisierung von Grundelementen in Ihrem Objekt anpassen möchten, müssen Sie Ihren eigenen Serializer für das Objekt schreiben. Sie können sich nicht auf die POJO Jackson-Serialisierung verlassen.
quelle
Jacksons JSON-Ansichten sind möglicherweise eine einfachere Möglichkeit, Ihre Anforderungen zu erfüllen, insbesondere wenn Sie in Ihrem JSON-Format eine gewisse Flexibilität haben.
Wenn dies
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
eine akzeptable Darstellung ist, ist dies mit sehr wenig Code sehr einfach zu erreichen.Sie würden lediglich das Namensfeld des Benutzers als Teil einer Ansicht mit Anmerkungen versehen und eine andere Ansicht in Ihrer Serialisierungsanforderung angeben (die nicht mit Anmerkungen versehenen Felder wären standardmäßig enthalten).
Zum Beispiel: Definieren Sie die Ansichten:
Kommentieren Sie den Benutzer:
Und serialisieren Sie das Anfordern einer Ansicht, die nicht das Feld enthält, das Sie ausblenden möchten (nicht kommentierte Felder werden standardmäßig serialisiert):
quelle
createdBy
als Wert statt als Objekt zu erhalten?setSerializationView()
scheinen veraltet zu sein, also habe ichmapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
stattdessen verwendet.In meinem Fall (Spring 3.2.4 und Jackson 2.3.1), XML-Konfiguration für benutzerdefinierten Serializer:
wurde auf unerklärliche Weise von etwas auf Standard zurückgeschrieben.
Das hat bei mir funktioniert:
CustomObject.java
CustomObjectSerializer.java
In
<mvc:message-converters>(...)</mvc:message-converters>
meiner Lösung ist keine XML-Konfiguration ( ) erforderlich.quelle
Wenn Ihre einzige Anforderung in Ihrem benutzerdefinierten Serializer darin besteht, das Serialisieren des
name
Felds von zu überspringenUser
, markieren Sie es als vorübergehend . Jackson wird transient nicht serialisieren oder deserialisieren Felder .[siehe auch: Warum hat Java Übergangsfelder? ]]
quelle
User
Klasse? Aber ich werde auch alle Benutzerobjekte serialisieren. ZB zuerst nur alle serialisierenitems
(nuruserId
als Referenz auf das Benutzerobjekt) und dann alle serialisierenusers
. In diesem Fall kann ich die Felder in derUser
Klasse nicht markieren .handledType()
Methode in der Dokumentation, mit der ich verlinkt habe, und wenn Eclipse die Methoden zur Implementierung von nohandledType()
generiert, wird sie generiert, daher bin ich verwirrt.Sie müssen die Methode handleType überschreiben und alles wird funktionieren
quelle
Das Problem in Ihrem Fall ist, dass dem ItemSerializer die Methode handleType () fehlt, die von JsonSerializer überschrieben werden muss
Daher erhalten Sie den expliziten Fehler, dass handleType () nicht definiert ist
Hoffe es hilft jemandem. Danke, dass Sie meine Antwort gelesen haben.
quelle