Mam dwie klasy Java, które chcę serializować do JSON przy użyciu Jacksona:
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;
}
}
Chcę serializować element do tego JSON:
{"id":7, "itemNr":"TEST", "createdBy":3}
z serializacją użytkownika, aby zawierał tylko id
. Będę również mógł serilizować wszystkie obiekty użytkownika do JSON, takie jak:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Więc myślę, że muszę napisać niestandardowy serializator Item
i wypróbować z tym:
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();
}
}
Serializuję JSON za pomocą tego kodu z 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();
}
Ale pojawia się ten błąd:
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)
Jak mogę używać niestandardowego serializatora z Jacksonem?
Tak bym to zrobił z Gsonem:
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);
Ale muszę to teraz zrobić z Jacksonem, ponieważ Gson nie obsługuje interfejsów.
java
json
serialization
jackson
Jonas
źródło
źródło
Item
? Mam problem polegający na tym, że moja metoda kontrolera zwraca standardowy serializowany obiektTypeA
, ale dla innej określonej metody kontrolera chcę serializować go inaczej. Jakby to wyglądało?Odpowiedzi:
Jak wspomniano, @JsonValue to dobry sposób. Ale jeśli nie masz nic przeciwko niestandardowemu serializatorowi, nie musisz pisać go dla elementu, ale raczej dla użytkownika - jeśli tak, byłoby to tak proste, jak:
Jeszcze inną możliwością jest wdrożenie
JsonSerializable
, w którym to przypadku nie jest wymagana rejestracja.Co do błędu; to dziwne - prawdopodobnie chcesz uaktualnić do nowszej wersji. Ale bezpieczniej jest też rozszerzyć,
org.codehaus.jackson.map.ser.SerializerBase
ponieważ będzie miał standardowe implementacje metod nieistotnych (tj. Wszystko oprócz rzeczywistego wywołania serializacji).źródło
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)
Możesz umieścić
@JsonSerialize(using = CustomDateSerializer.class)
dowolne pole daty obiektu do serializacji.źródło
@JsonSerialize(contentUsing= ...)
podczas adnotacji kolekcji (np.@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)Ja też próbowałem to zrobić, ale w przykładowym kodzie na stronie internetowej Jacksona jest błąd, który nie zawiera typu (
.class
) w wywołaniuaddSerializer()
metody, co powinno wyglądać następująco:Innymi słowy, są to wiersze, które tworzą instancję
simpleModule
i dodają serializator (z uprzednią niepoprawną linią wykomentowaną):FYI: Oto odniesienie do prawidłowego przykładowego kodu: http://wiki.fasterxml.com/JacksonFeatureModules
źródło
Użyj @JsonValue:
@JsonValue działa tylko na metodach, więc musisz dodać metodę getId. Powinieneś móc całkowicie pominąć swój niestandardowy serializator.
źródło
Napisałem przykład niestandardowej
Timestamp.class
serializacji / deserializacji, ale możesz go używać do wszystkiego, co chcesz.Podczas tworzenia mapowania obiektów zrób coś takiego:
na przykład w
java ee
możesz zainicjować go tym:gdzie serializator powinien wyglądać mniej więcej tak:
i deserializator coś takiego:
źródło
Oto wzorce zachowania, które zauważyłem, próbując zrozumieć serializację Jacksona.
1) Załóżmy, że istnieje obiekt Klasa i klasa Uczeń. Dla ułatwienia wszystko upubliczniłem i ostatecznie
2) Załóżmy, że są to serializatory, których używamy do serializacji obiektów do formatu JSON. WriteObjectField używa własnego serializatora obiektu, jeśli jest zarejestrowany w programie odwzorowującym obiekty; jeśli nie, to serializuje go jako POJO. WriteNumberField przyjmuje wyłącznie prymitywy jako argumenty.
3) Zarejestruj tylko DoubleSerializer z wzorcem wyjściowym DecimalFormat
###,##0.000
, w SimpleModule, a wynik to:Możesz zobaczyć, że serializacja POJO rozróżnia double i Double, używając DoubleSerialzer for Doubles i używając zwykłego formatu String dla podwójnych.
4) Zarejestruj DoubleSerializer i ClassroomSerializer, bez StudentSerializer. Spodziewamy się, że wynik jest taki, że jeśli napiszemy double jako obiekt, zachowuje się jak Double, a jeśli napiszemy Double jako liczbę, zachowuje się jak double. Zmienna instancji Student powinna być zapisana jako POJO i postępować zgodnie z powyższym wzorcem, ponieważ nie jest rejestrowana.
5) Zarejestruj wszystkie serializatory. Wynik to:
dokładnie tak, jak oczekiwano.
Kolejna ważna uwaga: jeśli masz wiele serializatorów dla tej samej klasy zarejestrowanych w tym samym module, moduł wybierze serializator dla tej klasy, która została ostatnio dodana do listy. Nie należy tego używać - jest to mylące i nie jestem pewien, jak spójne jest to
Morał: jeśli chcesz dostosować serializację prymitywów w swoim obiekcie, musisz napisać własny serializator dla obiektu. Nie możesz polegać na serializacji POJO Jackson.
źródło
Widoki JSON Jacksona mogą być prostszym sposobem spełnienia twoich wymagań, zwłaszcza jeśli masz pewną elastyczność w swoim formacie JSON.
Jeśli
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
jest to akceptowalna reprezentacja, będzie to bardzo łatwe do osiągnięcia przy bardzo małej ilości kodu.Po prostu dodasz adnotację do pola nazwy użytkownika jako część widoku i określ inny widok w żądaniu serializacji (pola bez adnotacji zostaną uwzględnione domyślnie)
Na przykład: Zdefiniuj widoki:
Opisz użytkownika:
I serializowanie żądające widoku, który nie zawiera pola, które chcesz ukryć (pola bez adnotacji są domyślnie serializowane):
źródło
createdBy
jako wartość zamiast jako obiekt?setSerializationView()
wydają się być przestarzałe, więcmapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
zamiast tego użyłem .W moim przypadku (Spring 3.2.4 i Jackson 2.3.1), konfiguracja XML dla niestandardowego serializatora:
został w niewyjaśniony sposób przez coś nadpisany z powrotem do wartości domyślnej.
To zadziałało dla mnie:
CustomObject.java
CustomObjectSerializer.java
<mvc:message-converters>(...)</mvc:message-converters>
W moim rozwiązaniu nie jest wymagana konfiguracja XML ( ).źródło
Jeśli jedynym wymaganiem w niestandardowym serializatorze jest pominięcie serializacji
name
polaUser
, oznacz je jako przejściowe . Jackson nie będzie serializować ani deserializować pól przejściowych .[zobacz także: Dlaczego Java ma pola przejściowe? ]
źródło
User
? Ale zserializuję również wszystkie obiekty użytkowników. Np. Najpierw serializuj wszystkoitems
(tylkouserId
jako odniesienie do obiektu użytkownika), a następnie serializuj wszystkousers
. W tym przypadku nie mogę zaznaczyć pól wUser
-class.handledType()
metodzie w dokumentacji, z którą się łączyłem, a kiedy Eclipse generuje metody do implementacji niehandledType()
jest generowane, więc jestem zdezorientowany.Musisz nadpisać metodę handledType i wszystko będzie działać
źródło
Problem w Twoim przypadku polega na tym, że w ItemSerializer brakuje metody handledType (), która musi zostać zastąpiona przez JsonSerializer
W związku z tym otrzymujesz jawny błąd, że nie zdefiniowano metody handledType ()
Mam nadzieję, że to komuś pomoże. Dziękuję za przeczytanie mojej odpowiedzi.
źródło