Serialisasi Jackson: abaikan nilai kosong (atau nol)

138

Saat ini saya menggunakan jackson 2.1.4 dan saya mengalami beberapa masalah mengabaikan bidang ketika saya mengonversi objek ke string JSON.

Inilah kelas saya yang bertindak sebagai objek yang akan dikonversi:

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;
    }
}
}

Dan inilah cara saya mengonversinya:

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())

Inilah hasilnya:

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

Bagaimana saya bisa menghindari nilai-nilai nol itu? Saya hanya ingin mengambil informasi yang diperlukan untuk tujuan "berlangganan"!

Inilah persis keluaran yang saya cari:

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

Saya juga mencoba @JsonInclude (Include.NON_NULL) dan meletakkan semua variabel saya ke nol, tetapi tidak berhasil juga! Terima kasih atas bantuannya kalian!

Shinnyx
sumber

Jawaban:

247

Anda memiliki anotasi di tempat yang salah - itu harus di kelas, bukan di lapangan. yaitu:

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

Seperti disebutkan dalam komentar, dalam versi di bawah 2.x sintaks untuk penjelasan ini adalah:

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

Pilihan lainnya adalah mengkonfigurasi ObjectMappersecara langsung, cukup dengan menelepon mapper.setSerializationInclusion(Include.NON_NULL);

(sebagai catatan, saya pikir popularitas jawaban ini merupakan indikasi bahwa anotasi ini harus dapat diterapkan pada bidang per bidang, @ fasterxml)

menggambar moore
sumber
Benar-benar tidak ada cara untuk membuat anotasi include.NON_NULL berfungsi? Atau yang NON_EMTPY? Karena saya tahu yang mana yang akan menjadi nol, tetapi itu tergantung pada situasinya. Saya menggunakan kelas "JsonOperation" yang sama untuk setiap objek yang ingin saya serialkan / deserialize dan saya hanya menginisialisasi variabel yang perlu saya gunakan tergantung pada situasinya. Apakah ini cara yang baik untuk melakukannya atau saya harus melakukan beberapa kelas yang hanya berisi variabel yang saya butuhkan (dengan cara itu saya tidak perlu menggunakan anotasi apa pun, karena tidak akan pernah ada variabel nol / kosong)
Shinnyx
26
Sintaks telah berubah dalam versi terbaru ke @JsonSerialize (termasuk = JsonSerialize.Inclusion.NON_NULL) dan @JsonSerialize (include = JsonSerialize.Inclusion.NON_EMPTY Jika Anda membutuhkan keduanya, non-null dan non-kosong, gunakan @JsonSerialize (termasuk = JsonSerialize) .Inclusion.NON_DEFAULT)
Maciej
1
Gunakan @JsonSerialize (termasuk = Penyertaan.NON_NULL) sebelum kelas atau sebelum properti berfungsi ...
swan
1
@rewmoore tolong periksa lagi, @JsonInclude(JsonSerialize.Inclusion.NON_NULL) harus @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)dan juga itu cara lama yang sudah usang. jadi Anda harus menulis "dalam versi di bawah 2.x", bukan "dalam versi 2.x +"
WestFarmer
2
2. + gunakan@JsonInclude(Include.NON_NULL)
Honghe.Wu
48

Anda juga dapat mengatur opsi global:

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
pengembara
sumber
15

Anda juga dapat mencoba menggunakannya

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

jika Anda berurusan dengan jackson dengan versi di bawah 2+ (1.9.5) saya mengujinya, Anda dapat dengan mudah menggunakan anotasi ini di atas kelas. Bukan untuk ditentukan untuk atribut, hanya untuk deklerasi kelas.

erhanasikoglu
sumber
2
termasuk atribut JsonSerialize sudah usang dalam mendukung JsonInclude
fd8s0
2
seperti yang saya katakan: dengan jackson dengan versi di bawah 2+ (1.9.5)
erhanasikoglu
pertanyaannya menanyakan tentang versi tertentu 2.1.4
fd8s0
14

Anda perlu menambahkan import com.fasterxml.jackson.annotation.JsonInclude;

Menambahkan

@JsonInclude(JsonInclude.Include.NON_NULL)

di atas POJO

Jika Anda memiliki POJO bersarang maka

@JsonInclude(JsonInclude.Include.NON_NULL)

perlu menambahkan pada setiap nilai.

CATATAN: JAXRS (Jersey) secara otomatis menangani skenario ini 2.6 dan lebih tinggi.

vaquar khan
sumber
apakah ada fungsi serupa ketika menggunakan paket org.codehaus.jackson.annotate lama?
pkran
Ya, Anda dapat menambahkan contoh metode pengambil di atas private int id; @JsonIgnore public int getId () {return id; }
vaquar khan
1
Sama dengan jawaban yang ada
Karl Richter
4

Untuk jackson 2.x

@JsonInclude(JsonInclude.Include.NON_NULL)

tepat sebelum lapangan.

Gere
sumber
2
Sama dengan jawaban yang ada
Karl Richter
2

Saya mengalami masalah yang sama baru-baru ini dengan versi 2.6.6.

@JsonInclude(JsonInclude.Include.NON_NULL)

Menggunakan anotasi di atas baik pada tingkat yang diajukan atau kelas tidak berfungsi seperti yang diharapkan. POJO bisa berubah ketika saya menerapkan anotasi. Ketika saya mengubah perilaku POJO menjadi tidak berubah, penjelasannya menghasilkan keajaiban.

Saya tidak yakin apakah itu turun ke versi baru atau versi sebelumnya dari lib ini memiliki perilaku yang sama tetapi untuk 2.6.6 tentu saja Anda perlu memiliki POJO Immutable agar penjelasannya dapat berfungsi.

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Opsi di atas disebutkan dalam berbagai jawaban pengaturan penyertaan serialisasi di ObjectMapper langsung di tingkat global juga berfungsi, tetapi, saya lebih suka mengendalikannya di tingkat kelas atau tingkat yang diarsipkan.

Jadi, jika Anda ingin semua bidang nol diabaikan sementara serialisasi JSON maka gunakan anotasi di tingkat kelas tetapi jika Anda ingin hanya beberapa bidang diabaikan di kelas maka gunakan bidang-bidang tertentu. Dengan cara ini lebih mudah dibaca & mudah untuk pemeliharaan jika Anda ingin mengubah perilaku untuk respons spesifik.

Amrut
sumber
2

Atau Anda dapat menggunakan GSON [ https://code.google.com/p/google-gson/ ], tempat bidang nol ini akan dihapus secara otomatis.

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));
    }
}

KELUARAN:

{"isLoggedIn":false}

Saya menggunakan gson-2.2.4

anij
sumber
-1

Kode di bawah ini dapat membantu jika Anda ingin mengecualikan tipe boolean dari serialisasi:

@JsonInclude(JsonInclude.Include.NON_ABSENT)
Alexander
sumber
1
Sama dengan jawaban yang ada
Karl Richter