Hanya menggunakan @JsonIgnore selama serialisasi, tetapi tidak deserialisasi

325

Saya memiliki objek pengguna yang dikirim ke dan dari server. Ketika saya mengirimkan objek pengguna, saya tidak ingin mengirim kata sandi hash ke klien. Jadi, saya menambahkan @JsonIgnorepada properti kata sandi, tetapi ini juga memblokirnya dari deserialized ke kata sandi yang membuatnya sulit untuk mendaftar pengguna ketika mereka tidak mendapat kata sandi.

Bagaimana saya bisa @JsonIgnoremenerapkan serialisasi dan bukan deserialisasi? Saya menggunakan Spring JSONView, jadi saya tidak punya banyak kendali atas ObjectMapper.

Hal yang saya coba:

  1. Tambahkan @JsonIgnoreke properti
  2. Tambahkan @JsonIgnorepada metode pengambil saja
chubbsondubs
sumber

Jawaban:

481

Cara melakukannya tergantung pada versi Jackson yang Anda gunakan. Ini berubah sekitar versi 1.9 , sebelum itu, Anda bisa melakukan ini dengan menambahkan @JsonIgnoreke pengambil.

Yang telah Anda coba:

Tambahkan @JsonIgnore pada metode pengambil saja

Lakukan ini, dan juga tambahkan @JsonPropertyanotasi khusus untuk nama bidang "kata sandi" JSON Anda ke metode penyetel kata sandi pada objek Anda.

Jackson versi terbaru telah menambahkan READ_ONLYdan WRITE_ONLYargumen penjelasan untuk JsonProperty. Jadi Anda juga bisa melakukan sesuatu seperti:

@JsonProperty(access = Access.WRITE_ONLY)
private String password;

Documents dapat ditemukan di sini .

pb2q
sumber
2
gist.github.com/thurloat/2510887 untuk Jackson JSON abaikan saja deserialize
Hadas
1
AFAIK Anda masih harus mengimplementasikan setter dan membubuhi keterangan. Saya hanya ingin getter untuk serialisasi. Apa transien yang Anda bicarakan? Itu anotasi JPA AFAIK
Matt Broekhuis
3
Juga, pastikan untuk menghapus @JsonProperty dari bidang itu sendiri jika tidak maka akan mengganti anotasi pengambil / penyetel Anda
Anton Soradoi
15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Mikhail Batcer
1
Jackson-annotations 2.5 tidak memiliki fitur yang lebih baru. Jackson-annotations 2.6.3 tidak
radiantRazor
98

Untuk mencapai ini, yang kita butuhkan hanyalah dua penjelasan:

  1. @JsonIgnore
  2. @JsonProperty

Gunakan @JsonIgnorepada anggota kelas dan pengambilnya, dan @JsonPropertypada setternya. Contoh ilustrasi akan membantu untuk melakukan ini:

class User {

    // More fields here
    @JsonIgnore
    private String password;

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

    @JsonProperty
    public void setPassword(final String password) {
        this.password = password;
    }
}
Balaji Boggaram Ramanarayan
sumber
2
itu satu-satunya yang bekerja untuk saya dengan jackson 2.6.4. Saya mencoba yang terbaik untuk menggunakan @JsonProperty (akses = Access.WRITE_ONLY) tetapi tidak berhasil untuk saya.
cirovladimir
77

Karena versi 2.6: cara yang lebih intuitif adalah dengan menggunakan com.fasterxml.jackson.annotation.JsonPropertyanotasi di lapangan:

@JsonProperty(access = Access.WRITE_ONLY)
private String myField;

Bahkan jika pengambil ada, nilai bidang dikecualikan dari serialisasi.

JavaDoc mengatakan:

/**
 * Access setting that means that the property may only be written (set)
 * for deserialization,
 * but will not be read (get) on serialization, that is, the value of the property
 * is not included in serialization.
 */
WRITE_ONLY

Jika Anda membutuhkannya, gunakan saja Access.READ_ONLY.

Daniel Beer
sumber
1
Saya tidak mengerti mengapa ada sedikit upvotes, ini cara yang elegan untuk menyelesaikan masalah ini, bekerja seperti pesona. Tidak perlu membubuhi keterangan pengambil, penyetel, dan bidang. Hanya bidang. Terima kasih.
CROSP
Ini tersedia sejak versi 2.6, lihat fastxml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer
Mungkin jawaban terbaik untuk pengguna 2.6+.
David Dossot
Pastikan Anda tidak menggunakan impor org.codehaus.jackson.annotate . @ Solusi DanielBeer bekerja untuk Jackson 2.6.3. Ini harus menjadi jawaban yang diterima sekarang karena Jackson telah diperbarui.
Kent Bull
13

Dalam kasus saya, saya memiliki Jackson secara otomatis (de) serialisasi objek yang saya kembali dari pengendali Spring MVC (saya menggunakan @RestController dengan Spring 4.1.6). Saya harus menggunakan com.fasterxml.jackson.annotation.JsonIgnoredaripada org.codehaus.jackson.annotate.JsonIgnore, karena jika tidak, itu tidak melakukan apa-apa.

Alex Beardsley
sumber
1
ini adalah jawaban yang sangat berguna yang benar-benar membantu saya menemukan sumber mengapa @JsonIgnore tidak dihormati oleh Jackson ... terima kasih!
Clint Eastwood
2
"user": {
        "firstName": "Musa",
        "lastName": "Aliyev",
        "email": "[email protected]",
        "passwordIn": "98989898", (or encoded version in front if we not using https)
        "country": "Azeribaijan",
        "phone": "+994707702747"
    }

@CrossOrigin(methods=RequestMethod.POST)
@RequestMapping("/public/register")
public @ResponseBody MsgKit registerNewUsert(@RequestBody User u){

        root.registerUser(u);

    return new MsgKit("registered");
}  

@Service
@Transactional
public class RootBsn {

    @Autowired UserRepository userRepo;

    public void registerUser(User u) throws Exception{

        u.setPassword(u.getPasswordIn());
        //Generate some salt and  setPassword (encoded -  salt+password)
        User u=userRepo.save(u);

        System.out.println("Registration information saved");
    }

}

    @Entity        
@JsonIgnoreProperties({"recordDate","modificationDate","status","createdBy","modifiedBy","salt","password"})
                    public class User implements Serializable {
                        private static final long serialVersionUID = 1L;

                        @Id
                        @GeneratedValue(strategy=GenerationType.AUTO)
                        private Long id;

                        private String country;

                        @Column(name="CREATED_BY")
                        private String createdBy;

                        private String email;

                        @Column(name="FIRST_NAME")
                        private String firstName;

                        @Column(name="LAST_LOGIN_DATE")
                        private Timestamp lastLoginDate;

                        @Column(name="LAST_NAME")
                        private String lastName;

                        @Column(name="MODIFICATION_DATE")
                        private Timestamp modificationDate;

                        @Column(name="MODIFIED_BY")
                        private String modifiedBy;

                        private String password;

                        @Transient
                        private String passwordIn;

                        private String phone;

                        @Column(name="RECORD_DATE")
                        private Timestamp recordDate;

                        private String salt;

                        private String status;

                        @Column(name="USER_STATUS")
                        private String userStatus;

                        public User() {
                        }
                // getters and setters
                }
Musa
sumber
4
Di masa mendatang mungkin akan membantu memberikan deskripsi singkat tentang cara kerja kode.
KWILLIAMS
Baik !! Apa yang kamu coba di sini? Mendapat lebih banyak suara? lol
Balaji Boggaram Ramanarayan
0

Cara mudah lain untuk menangani ini adalah dengan menggunakan argumen allowSetters=truedalam anotasi. Ini akan memungkinkan kata sandi untuk di-deserialisasi ke dto Anda, tetapi kata sandi itu tidak akan diserialisasi ke badan respons yang menggunakan objek berisi.

contoh:

@JsonIgnoreProperties(allowSetters = true, value = {"bar"})
class Pojo{
    String foo;
    String bar;
}

Keduanya foodan bardihuni dalam objek, tetapi hanya foo ditulis ke dalam tubuh respons.

Dhandley
sumber
Itu kesalahan saya, saya tidak sadar Anda sudah mengoreksi cuplikannya. Melihat perubahan Anda, tampaknya tahun-tahun penulisan saya di Groovy membuat saya dan terjemahan saya ke Jawa agak kasar. Maaf!
Dhandley