Serializacja Jacksona: ignoruj ​​puste wartości (lub null)

138

Obecnie używam jackson 2.1.4 i mam problemy z ignorowaniem pól podczas konwertowania obiektu na ciąg JSON.

Oto moja klasa, która działa jako obiekt do konwersji:

public class JsonOperation {

public static class Request {
    @JsonInclude(Include.NON_EMPTY)
    String requestType;
    Data data = new Data();

    public static class Data {
        @JsonInclude(Include.NON_EMPTY)
        String username;
        String email;
        String password;
        String birthday;
        String coinsPackage;
        String coins;
        String transactionId;
        boolean isLoggedIn;
    }
}

public static class Response {
    @JsonInclude(Include.NON_EMPTY)
    String requestType = null;
    Data data = new Data();

    public static class Data {
        @JsonInclude(Include.NON_EMPTY)
        enum ErrorCode { ERROR_INVALID_LOGIN, ERROR_USERNAME_ALREADY_TAKEN, ERROR_EMAIL_ALREADY_TAKEN };
        enum Status { ok, error };

        Status status;
        ErrorCode errorCode;
        String expiry;
        int coins;
        String email;
        String birthday;
        String pictureUrl;
        ArrayList <Performer> performer;
    }
}
}

A oto jak to konwertuję:

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

JsonOperation subscribe = new JsonOperation();

subscribe.request.requestType = "login";

subscribe.request.data.username = "Vincent";
subscribe.request.data.password = "test";


Writer strWriter = new StringWriter();
try {
    mapper.writeValue(strWriter, subscribe.request);
} catch (JsonGenerationException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (JsonMappingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Log.d("JSON", strWriter.toString())

Oto wynik:

{"data":{"birthday":null,"coins":null,"coinsPackage":null,"email":null,"username":"Vincent","password":"test","transactionId":null,"isLoggedIn":false},"requestType":"login"}

Jak mogę uniknąć tych wartości null? Chcę tylko pobrać wymagane informacje w celu „subskrypcji”!

Oto dokładnie wynik, którego szukam:

{"data":{"username":"Vincent","password":"test"},"requestType":"login"}

Próbowałem też @JsonInclude (Include.NON_NULL) i ustawiłem wszystkie moje zmienne na null, ale to też nie działało! Dzięki za pomoc!

Shinnyx
źródło

Odpowiedzi:

247

Masz adnotację w niewłaściwym miejscu - musi znajdować się na zajęciach, a nie w polu. to znaczy:

@JsonInclude(Include.NON_NULL) //or Include.NON_EMPTY, if that fits your use case 
public static class Request {
  // ...
}

Jak zauważono w komentarzach, w wersjach poniżej 2.x składnia tej adnotacji jest następująca:

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) // or JsonSerialize.Inclusion.NON_EMPTY

Inną opcją jest ObjectMapperbezpośrednia konfiguracja , po prostu dzwoniąc mapper.setSerializationInclusion(Include.NON_NULL);

(dla porządku, myślę, że popularność tej odpowiedzi wskazuje, że ta adnotacja powinna mieć zastosowanie w poszczególnych polach, @fasterxml)

Drew Moore
źródło
Naprawdę nie ma sposobu, aby adnotacja include.NON_NULL działała? Albo NON_EMTPY? Bo wiem, który z nich będzie zerowy, ale to zależy od sytuacji. Używam tej samej klasy „JsonOperation” dla każdego obiektu, który chcę serializować / deserializować i inicjalizuję tylko zmienne, których potrzebuję, w zależności od sytuacji. Czy to dobry sposób, czy powinienem zrobić kilka klas zawierających tylko zmienne, których potrzebuję (w ten sposób nie musiałbym używać adnotacji, ponieważ nigdy nie będzie pustej / pustej zmiennej)
Shinnyx
26
W najnowszej wersji składnia została zmieniona na @JsonSerialize (include = JsonSerialize.Inclusion.NON_NULL) i @JsonSerialize (include = JsonSerialize.Inclusion.NON_EMPTY Jeśli potrzebujesz zarówno wartości niezerowej, jak i niepustej, użyj @JsonSerialize (include = JsonSerialize .Inclusion.NON_DEFAULT)
Maciej
1
Użyj @JsonSerialize (include = Inclusion.NON_NULL) przed zajęciami lub przed właściwością, która zadziałała ...
łabędź
1
@drewmoore, sprawdź ponownie, @JsonInclude(JsonSerialize.Inclusion.NON_NULL) powinno być, @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)a także jest to stary przestarzały sposób. więc powinieneś napisać „w wersji poniżej 2.x”, a nie „w wersji 2.x +”
WestFarmer
2
2. + użycie@JsonInclude(Include.NON_NULL)
Honghe.Wu
48

Możesz także ustawić opcję globalną:

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
koczownik
źródło
15

Możesz także spróbować użyć

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

jeśli masz do czynienia z jacksonem z wersją poniżej 2+ (1.9.5) to testowałem to bez problemu możesz użyć tej adnotacji nad klasą. Nie dla określonych dla atrybutów, tylko dla dekleracji klas.

erhanasikoglu
źródło
2
include atrybut JsonSerialize jest przestarzały na korzyść JsonInclude
fd8s0
2
tak jak powiedziałem: z jacksonem z wersją poniżej 2+ (1.9.5)
erhanasikoglu
pytanie dotyczy konkretnej wersji 2.1.4
fd8s0
14

Musisz dodać import com.fasterxml.jackson.annotation.JsonInclude;

Dodaj

@JsonInclude(JsonInclude.Include.NON_NULL)

na szczycie POJO

Jeśli masz zagnieżdżone POJO, to

@JsonInclude(JsonInclude.Include.NON_NULL)

trzeba dodać wszystkie wartości.

UWAGA: JAXRS (Jersey) automatycznie obsługuje ten scenariusz 2.6 i nowsze.

vaquar khan
źródło
czy istnieje podobna funkcjonalność w przypadku korzystania ze starego pakietu org.codehaus.jackson.annotate?
pkran
Tak, możesz dodać przykład metody pobierającej private int id; @JsonIgnore public int getId () {id powrotu; }
vaquar khan
1
Takie same jak istniejące odpowiedzi
Karl Richter
4

Dla jackson 2.x

@JsonInclude(JsonInclude.Include.NON_NULL)

tuż przed polem.

Gere
źródło
2
Takie same jak istniejące odpowiedzi
Karl Richter
2

Ostatnio miałem podobny problem z wersją 2.6.6.

@JsonInclude(JsonInclude.Include.NON_NULL)

Używanie powyższej adnotacji na poziomie pola lub klasy nie działało zgodnie z oczekiwaniami. POJO było zmienne, gdy stosowałem adnotację. Kiedy zmieniłem zachowanie POJO na niezmienne, adnotacja zadziałała magicznie.

Nie jestem pewien, czy jego nowa wersja lub poprzednie wersje tej biblioteki zachowywały się podobnie, ale dla 2.6.6 z pewnością musisz mieć Immutable POJO, aby adnotacja działała.

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Powyższa opcja wymieniona w różnych odpowiedziach dotyczących ustawiania włączenia serializacji w ObjectMapper bezpośrednio na poziomie globalnym również działa, ale wolę kontrolować ją na poziomie klasy lub pola.

Więc jeśli chcesz, aby wszystkie pola puste były ignorowane podczas serializacji JSON, użyj adnotacji na poziomie klasy, ale jeśli chcesz, aby tylko kilka pól w klasie było ignorowanych, użyj ich na tych określonych polach. W ten sposób jest bardziej czytelny i łatwy w utrzymaniu, jeśli chcesz zmienić zachowanie dla określonej odpowiedzi.

Amrut
źródło
2

Możesz też użyć GSON [ https://code.google.com/p/google-gson/ ], gdzie te puste pola zostaną automatycznie usunięte.

SampleDTO.java

public class SampleDTO {

    String username;
    String email;
    String password;
    String birthday;
    String coinsPackage;
    String coins;
    String transactionId;
    boolean isLoggedIn;

    // getters/setters
}

Test.java

import com.google.gson.Gson;

public class Test {

    public static void main(String[] args) {
        SampleDTO objSampleDTO = new SampleDTO();
        Gson objGson = new Gson();
        System.out.println(objGson.toJson(objSampleDTO));
    }
}

WYNIK:

{"isLoggedIn":false}

Użyłem gson-2.2.4

anij
źródło
-1

Poniższy kod może pomóc, jeśli chcesz wykluczyć typ boolowski z serializacji:

@JsonInclude(JsonInclude.Include.NON_ABSENT)
Alexander
źródło
1
Takie same jak istniejące odpowiedzi
Karl Richter