ใช้ @JsonIgnore เฉพาะระหว่างการทำให้เป็นอนุกรม แต่ไม่ใช่การดีซีเรียลไลเซชัน


325

ฉันมีวัตถุผู้ใช้ที่ส่งไปยังและจากเซิร์ฟเวอร์ เมื่อฉันส่งวัตถุผู้ใช้ออกฉันไม่ต้องการส่งรหัสผ่านที่แฮชไปยังไคลเอนต์ ดังนั้นฉันเพิ่ม@JsonIgnoreในคุณสมบัติรหัสผ่าน แต่ยังป้องกันไม่ให้ถูกดีซีเรียลไลซ์ลงในรหัสผ่านซึ่งทำให้ยากต่อการลงทะเบียนผู้ใช้เมื่อพวกเขาไม่ได้รับรหัสผ่าน

ฉัน@JsonIgnoreจะนำไปใช้กับการทำให้เป็นอนุกรมเท่านั้นและไม่ได้ทำการดีซีเรียลไลเซชัน? ฉันใช้ Spring JSONView ดังนั้นฉันจึงไม่สามารถควบคุมสิ่งObjectMapperต่างๆ

สิ่งที่ฉันได้ลอง:

  1. เพิ่ม@JsonIgnoreไปยังคุณสมบัติ
  2. เพิ่ม@JsonIgnoreในวิธี getter เท่านั้น

คำตอบ:


481

วิธีการทำสิ่งนี้ขึ้นอยู่กับรุ่นของ Jackson ที่คุณใช้งานอยู่ สิ่งนี้มีการเปลี่ยนแปลงรอบ ๆ เวอร์ชัน1.9ก่อนหน้านั้นคุณสามารถทำได้โดยการเพิ่ม@JsonIgnoreไปยังผู้ทะเยอทะยาน

สิ่งที่คุณได้ลอง:

เพิ่ม @JsonIgnore บนวิธี getter เท่านั้น

ทำสิ่งนี้และเพิ่ม@JsonPropertyหมายเหตุเฉพาะสำหรับชื่อฟิลด์ "รหัสผ่าน" JSON ของคุณไปยังเมธอด setter สำหรับรหัสผ่านบนวัตถุของคุณ

รุ่นอื่น ๆ ที่ผ่านมาของแจ็คสันได้เพิ่มREAD_ONLYและข้อโต้แย้งคำอธิบายประกอบสำหรับWRITE_ONLY JsonPropertyดังนั้นคุณสามารถทำสิ่งที่ชอบ:

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

เอกสารที่สามารถพบได้ที่นี่


2
gist.github.com/thurloat/2510887สำหรับแจ็คสัน JSON ไม่สนใจในdeserializeเท่านั้น
Hadas

1
AFAIK คุณยังต้องใช้ setter และใส่คำอธิบายประกอบ ฉันแค่ต้องการทะเยอทะยานสำหรับการทำให้เป็นอันดับ ชั่วคราวที่คุณพูดถึงคืออะไร? นั่นเป็นคำอธิบายประกอบ JPA AFAIK
Matt Broekhuis

3
นอกจากนี้ตรวจสอบให้แน่ใจว่าได้ลบ @JsonProperty ออกจากฟิลด์ด้วยตัวเองมิฉะนั้นจะมีการแทนที่คำอธิบายประกอบ getter / setter ของคุณ
Anton Soradoi

15
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Mikhail Batcer

1
Jackson-annotations 2.5 ไม่มีคุณลักษณะภายหลัง คำอธิบายประกอบที่แจ็กสัน 2.6.3 ใช้ได้
radiantRazor

98

ในการทำสิ่งนี้ให้สำเร็จสิ่งที่เราต้องการคือคำอธิบายประกอบสองข้อ:

  1. @JsonIgnore
  2. @JsonProperty

ใช้@JsonIgnoreกับสมาชิกชั้นเรียนและผู้ทะเยอทะยานและ@JsonPropertyผู้ตั้งค่า ภาพประกอบตัวอย่างจะช่วยในการทำสิ่งนี้:

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

2
มันเป็นสิ่งเดียวที่ทำงานกับฉันด้วยแจ็คสัน 2.6.4 ฉันพยายามอย่างดีที่สุดเพื่อใช้ @JsonProperty (access = Access.WRITE_ONLY) แต่มันไม่ได้ผลสำหรับฉัน
cirovladimir

77

ตั้งแต่เวอร์ชัน 2.6: วิธีที่ง่ายกว่าคือใช้com.fasterxml.jackson.annotation.JsonPropertyหมายเหตุประกอบบนฟิลด์:

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

แม้ว่า getter จะมีอยู่ค่าของฟิลด์จะถูกแยกออกจากการทำให้เป็นอนุกรม

JavaDoc พูดว่า:

/**
 * 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

ในกรณีที่คุณจำเป็นต้องใช้วิธีอื่น ๆ Access.READ_ONLYใช้เพียง


1
ฉันไม่เข้าใจว่าทำไมมี upvotes น้อยมากนี่เป็นวิธีที่ยอดเยี่ยมในการแก้ปัญหานี้ทำงานเหมือนมีเสน่ห์ ไม่จำเป็นต้องใส่หมายเหตุประกอบ getter, setter และ field ฟิลด์เดียว ขอบคุณ
CROSP

สิ่งนี้มีให้ตั้งแต่รุ่น 2.6 ดูได้เร็วขึ้นxml.github.io/jackson-annotations/javadoc/2.6/com/…
Daniel Beer

อาจเป็นคำตอบที่ดีที่สุดสำหรับผู้ใช้มากกว่า 2.6 คน
David Dossot

ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้การนำเข้าorg.codehaus.jackson.annotate โซลูชันของ @ DanielBeer ใช้งานได้กับแจ็คสัน 2.6.3 นี่ควรเป็นคำตอบที่ยอมรับในขณะนี้ที่แจ็คสันได้รับการปรับปรุง
Kent Bull

13

ในกรณีของฉันฉันมี Jackson (de) การทำให้เป็นอันดับวัตถุที่ฉันกลับมาจากคอนโทรลเลอร์ Spring MVC (ฉันใช้ @RestController กับ Spring 4.1.6) ฉันต้องใช้com.fasterxml.jackson.annotation.JsonIgnoreแทนorg.codehaus.jackson.annotate.JsonIgnoreมิฉะนั้นก็ไม่ได้ทำอะไรเลย


1
นี่เป็นคำตอบที่มีประโยชน์อย่างยิ่งที่ช่วยฉันค้นหาสาเหตุที่ @JsonIgnore ไม่ได้รับเกียรติจาก Jackson ... ขอบคุณ!
Clint Eastwood

2
"user": {
        "firstName": "Musa",
        "lastName": "Aliyev",
        "email": "klaudi2012@gmail.com",
        "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
                }

4
มันอาจช่วยในอนาคตเพื่อให้แม้แต่คำอธิบายสั้น ๆ เกี่ยวกับวิธีการทำงานของรหัส
KWILLIAMS

เอาล่ะ !! คุณพยายามทำอะไรที่นี่ รับคะแนนโหวตเพิ่มขึ้น? lol
Balaji Boggaram Ramanarayan

0

อีกวิธีที่ง่ายในการจัดการสิ่งนี้คือการใช้อาร์กิวเมนต์allowSetters=trueในคำอธิบายประกอบ นี่จะอนุญาตให้รหัสผ่านถูก deserialized ใน dto ของคุณ แต่มันจะไม่ทำให้เป็นอนุกรมมันเป็นเนื้อหาการตอบสนองที่ใช้มีวัตถุ

ตัวอย่าง:

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

ทั้งสองfooและbarมีประชากรในวัตถุ แต่มีเพียง foo เท่านั้นที่เขียนลงในเนื้อความการตอบสนอง


นั่นเป็นความผิดพลาดของฉันฉันไม่ทราบว่าคุณได้แก้ไขข้อมูลโค้ดแล้ว เมื่อดูการเปลี่ยนแปลงของคุณดูเหมือนว่าการเขียนของฉันใน Groovy เป็นเวลาหลายปีทำให้ฉันและการแปลภาษาจาวาของฉันหยาบ ขออภัย!
Dhandley
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.