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?


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.


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

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

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

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

10

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


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

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

0

atur variabel sebagai

@JsonIgnore

Ini memungkinkan variabel untuk dilewati oleh json serializer

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.