Jackson: bagaimana mencegah serialisasi lapangan

163

Saya memiliki kelas entitas dengan bidang kata sandi:

class User {
    private String password;

    //setter, getter..
}

Saya ingin bidang ini dilewati selama serialisasi. Tapi itu harus tetap bisa melakukan DEserialize. Ini diperlukan, agar klien dapat mengirim saya kata sandi baru, tetapi tidak dapat membaca yang sekarang.

Bagaimana saya melakukannya dengan Jackson?

minggu
sumber
1
Anda tidak ingin membuat cerita bersambung, tetapi Anda ingin dapat membatalkan deserialisasi? Itu tidak mungkin, kataku. Jika Anda tidak memasukkan cookie ke dalam kotak, Anda tidak akan dapat mengambilnya dari kotak ini.
Alexis Dufrenoy
1
@ Taroth: tapi saya bisa meletakkan cookie BARU. Saya hanya mencari penjelasan yang mudah, tetapi ini bisa dilakukan dengan tangan.
weekens
8
Komentar cepat: sangat mungkin, secara teknis, untuk memiliki setter yang digunakan (bahkan yang pribadi terdeteksi secara otomatis), dan hanya menghilangkan accessor (tidak ada bidang publik atau pengambil). Dimungkinkan juga untuk menambahkan @JsonIgnorepada pengambil, tetapi @JsonPropertypada penyetel, dalam hal ini hal-hal tidak serial, tetapi dapat deserialized.
StaxMan
4
Maukah Anda menerima jawaban untuk pertanyaan ini? (Beberapa yang lain berusia beberapa tahun & masih belum dapat diterima ... Harap pertimbangkan ulasan!) :) Pengungkapan penuh - Saya tidak punya jawaban untuk semua pertanyaan ini.
Barett

Jawaban:

187

Anda dapat menandainya sebagai @JsonIgnore.

Dengan 1.9, Anda dapat menambahkan @JsonIgnoreuntuk getter, @JsonPropertyuntuk setter, untuk membuatnya deserialize tetapi tidak serial.

Biju Kunjummen
sumber
6
@JsonIgnore juga mencegah deserialisasi. Untuk sementara - saya akan memeriksanya.
weekens
98
Dengan 1.9, Anda dapat menambahkan @JsonIgnoreuntuk getter, @JsonPropertyuntuk setter, untuk membuatnya deserialize tetapi tidak serial.
StaxMan
Komentar StaxMan harus menjadi jawabannya, bukan? Kenapa masih berkomentar kalau begitu ...! ..?
Saravanabalagi Ramachandran
sementara sepertinya tidak bekerja untuk saya, saya menandai bidang "sementara" yang saya tidak ingin menjadi serilized / deserialized.
rohith
Jawaban ini sebelumnya disarankan menggunakan transient(seperti dalam private transient String password;) tetapi bidang sementara dengan getter publik diabaikan kecuali MapperFeature.PROPAGATE_TRANSIENT_MARKER diaktifkan.
tom
96

Menggambarkan apa yang telah dikatakan StaxMan, ini bekerja untuk saya

private String password;

@JsonIgnore
public String getPassword() {
    return password;
}

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}
Gary
sumber
12
Ketergantungan Json mana yang Anda gunakan? Ini tidak berfungsi dengan com.fasterxml.jackson
Alexander Burakevych
3
Terima kasih! @JsonIgnoresepertinya tidak perlu di lapangan.
Ferran Maylinch
com.fasterxml.jackson.annotation.JsonIgnore dari jackson-annotations- <version> .jar
mvmn
Saya sudah mencoba ini dan itu tidak berhasil untuk saya. Saya menggunakan v2.8. Ada bantuan?
Maz
36

Cara mudah adalah dengan membuat anotasi getter dan setter Anda.

Berikut ini adalah contoh asli yang dimodifikasi untuk mengecualikan kata sandi teks biasa, tetapi kemudian menjelaskan metode baru yang hanya mengembalikan bidang kata sandi sebagai teks terenkripsi.

class User {

    private String password;

    public void setPassword(String password) {
        this.password = password;
    }

    @JsonIgnore
    public String getPassword() {
        return password;
    }

    @JsonProperty("password")
    public String getEncryptedPassword() {
        // encryption logic
    }
}
Joe Allen
sumber
21

Dimulai dengan Jackson 2.6 , properti dapat ditandai sebagai hanya baca atau tulis. Ini lebih sederhana daripada meretas anotasi pada kedua pengakses dan menyimpan semua informasi di satu tempat:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}
Frank Pavageau
sumber
Ini adalah solusi yang luar biasa, sederhana, bekerja. Terima kasih.
dhqvinh
17

Selain itu @JsonIgnore, ada beberapa kemungkinan lain:

  • Gunakan Tampilan JSON untuk memfilter bidang secara kondisional (secara default, tidak digunakan untuk deserialisasi; pada 2.0 akan tersedia tetapi Anda dapat menggunakan tampilan berbeda pada serialisasi, deserialisasi)
  • @JsonIgnoreProperties di kelas mungkin berguna
StaxMan
sumber
10

transientadalah solusi untuk saya. Terima kasih! itu asli ke Java dan menghindari Anda untuk menambahkan anotasi khusus kerangka lain.

maxxyme
sumber
2
Itu berfungsi jika atribut Anda benar-benar sementara, bukan ORM yang terlibat, misalnya .... Menemukan @JsonIgnore lebih menarik dalam kasus saya, meskipun saya akan dikunci ke jackson, tetapi itu adalah tradeoff yang bagus
Joao Pereira
3
Anda tidak harus dikunci ke jackson jika Anda membuat anotasi Anda sendiri dan memilikinya anotasi oleh JsonIgnore dan JacksonAnnotationsInside. Dengan begitu, jika Anda mengubah serialis, Anda hanya perlu mengubah anotasi Anda sendiri.
DavidA
4

Orang harus bertanya mengapa Anda menginginkan metode getter publik untuk kata sandi. Hibernate, atau kerangka kerja ORM lainnya, akan dilakukan dengan metode pengambil pribadi. Untuk memeriksa apakah kata sandi itu benar, Anda dapat menggunakan

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}
Albert Waninge
sumber
Saya benar-benar berpikir ini adalah cara terbaik untuk memikirkan solusinya. Lebih masuk akal untuk membuat hal-hal yang Anda butuhkan pribadi dan mengendalikannya dari objek itu sendiri.
arcynum
2

Jackson memiliki kelas bernama SimpleBeanPropertyFilter yang membantu memfilter bidang selama serialisasi dan deserialisasi; tidak secara global. Saya pikir itu yang Anda inginkan.

@JsonFilter("custom_serializer")
class User {
    private String password;

    //setter, getter..
}

Kemudian dalam kode Anda:

String[] fieldsToSkip = new String[] { "password" };

ObjectMapper mapper = new ObjectMapper();

final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("custom_serializer",
            SimpleBeanPropertyFilter.serializeAllExcept(fieldsToSkip));

mapper.setFilters(filter);

String jsonStr = mapper.writeValueAsString(currentUser);

Ini akan mencegah passwordbidang untuk mendapatkan serial. Anda juga akan dapat deserialize passwordbidang seperti itu. Pastikan tidak ada filter yang diterapkan pada objek ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(yourJsonStr, User.class);    // user object does have non-null password field
krhitesh
sumber
0

atur variabel sebagai

@JsonIgnore

Ini memungkinkan variabel untuk dilewati oleh json serializer

Pravin
sumber