Próbuję dołączyć surowy kod JSON do obiektu Java, gdy obiekt jest (de) serializowany przy użyciu Jacksona. Aby przetestować tę funkcjonalność, napisałem następujący test:
public static class Pojo {
public String foo;
@JsonRawValue
public String bar;
}
@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {
String foo = "one";
String bar = "{\"A\":false}";
Pojo pojo = new Pojo();
pojo.foo = foo;
pojo.bar = bar;
String json = "{\"foo\":\"" + foo + "\",\"bar\":" + bar + "}";
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(pojo);
System.out.println(output);
assertEquals(json, output);
Pojo deserialized = objectMapper.readValue(output, Pojo.class);
assertEquals(foo, deserialized.foo);
assertEquals(bar, deserialized.bar);
}
Kod wyświetla następujący wiersz:
{"foo":"one","bar":{"A":false}}
JSON jest dokładnie taki, jak chcę, aby wszystko wyglądało. Niestety, kod kończy się niepowodzeniem z wyjątkiem podczas próby odczytania JSON z powrotem do obiektu. Oto wyjątek:
org.codehaus.jackson.map.JsonMappingException: nie można deserializować instancji java.lang.String z START_OBJECT tokenu pod adresem [Źródło: java.io.StringReader@d70d7a; wiersz: 1, kolumna: 13] (przez łańcuch odniesienia: com.tnal.prism.cobalt.gather.testing.Pojo ["bar"])
Dlaczego Jackson działa dobrze w jednym kierunku, ale zawodzi, gdy idzie w drugim? Wygląda na to, że powinien być w stanie ponownie przyjąć własne wyjście jako dane wejściowe. Wiem, że to, co próbuję zrobić, jest nieortodoksyjne (ogólną radą jest utworzenie wewnętrznego obiektu, bar
który ma właściwość o nazwie A
), ale nie chcę w ogóle wchodzić w interakcje z tym JSONem. Mój kod działa jako przejście dla tego kodu - chcę pobrać ten JSON i wysłać go z powrotem bez dotykania niczego, ponieważ kiedy JSON się zmienia, nie chcę, aby mój kod wymagał modyfikacji.
Dzięki za radę.
EDYCJA: Zmieniono Pojo jako statyczną klasę, która powodowała inny błąd.
źródło
Podążając za odpowiedzią @StaxMan , wykonałem następujące czynności:
Aby być wiernym pierwszemu pytaniu, oto próba robocza:
źródło
getJson()
wString
końcu wraca . Jeśli po prostu zwróci to,JsonNode
co zostało ustawione przez setter, zostanie serializowany zgodnie z życzeniem, nie?node.asText()
zwraca przeciwną wartość pustątoString()
.Udało mi się to zrobić za pomocą niestandardowego deserializatora (wyciąć i wkleić stąd )
źródło
@JsonRawValue
@JsonSetter może pomóc. Zobacz moją próbkę („dane” powinny zawierać nieprzetworzony kod JSON):
źródło
Dodając do świetnej odpowiedzi Roya Truelove , oto jak wstrzyknąć niestandardowy deserializator w odpowiedzi na pojawienie się :
@JsonRawValue
źródło
To jest problem z twoimi wewnętrznymi klasami.
Pojo
Klasa jest niestatyczny klasy wewnętrzny od klasy badanej i Jackson nie może instancji tej klasy. Więc może serializować, ale nie deserializować.Przedefiniuj swoją klasę w ten sposób:
Zwróć uwagę na dodanie
static
źródło
To proste rozwiązanie zadziałało dla mnie:
Mogłem więc przechowywać surową wartość JSON w zmiennej rawJsonValue, a następnie nie było problemu z deserializacją (jako obiektu) z innymi polami z powrotem do JSON i wysłaniem przez mój REST. Używanie @JsonRawValue nie pomogło mi, ponieważ przechowywany JSON został zdeserializowany jako String, a nie jako obiekt, a nie tego chciałem.
źródło
Działa to nawet w jednostce JPA:
W idealnym przypadku ObjectMapper, a nawet JsonFactory pochodzą z kontekstu i są skonfigurowane tak, aby poprawnie obsługiwać JSON (na przykład standardowe lub niestandardowe wartości, takie jak „Infinity”).
źródło
JsonNode.toString()
dokumentacjąMethod that will produce developer-readable representation of the node; which may <b>or may not</b> be as valid JSON.
Jest to więc właściwie bardzo ryzykowna realizacja.JsonNode.asText()
wewnętrznie i wyprowadzi Infinity i inne niestandardowe wartości JSON.Oto pełny działający przykład, jak używać modułów Jacksona do
@JsonRawValue
pracy w obie strony (serializacja i deserializacja):Następnie możesz zarejestrować moduł po utworzeniu
ObjectMapper
:źródło
org.codehaus.jackson
pakietu bez zdawania sobie z tego sprawy. Upewnij się, że cały import pochodzi z plikucom.fasterxml.jackson
.Miałem dokładnie ten sam problem. Rozwiązanie znalazłem w tym poście: przeanalizuj drzewo JSON do zwykłej klasy przy użyciu Jacksona lub jego alternatyw
Sprawdź ostatnią odpowiedź. Po zdefiniowaniu niestandardowej metody ustawiającej dla właściwości, która przyjmuje JsonNode jako parametr i wywołuje metodę toString w jsonNode w celu ustawienia właściwości String, wszystko działa.
źródło
Korzystanie z obiektu działa dobrze w obie strony ... Ta metoda powoduje dwukrotną deserializację surowej wartości.
RawHello.java
RawJsonValue.java
źródło
Miałem podobny problem, ale używając listy z wieloma itensami JSON (
List<String>
).Udało mi się serializować za pomocą
@JsonRawValue
adnotacji. Ale do deserializacji musiałem stworzyć niestandardowy deserializator na podstawie sugestii Roya.Poniżej możesz zobaczyć mój deserializator „Lista”.
źródło