แจ็กสัน: วิธีการป้องกันการทำให้เป็นอันดับสนาม


163

ฉันมีคลาสเอนทิตีที่มีฟิลด์รหัสผ่าน:

class User {
    private String password;

    //setter, getter..
}

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

ฉันจะทำสิ่งนี้ให้สำเร็จด้วยแจ็คสันได้อย่างไร


1
คุณไม่ต้องการที่จะทำให้เป็นอันดับ แต่คุณต้องการที่จะสามารถ deserialize ได้หรือไม่ นั่นเป็นไปไม่ได้เลยฉันจะบอก หากคุณไม่ได้ใส่คุกกี้ไว้ในกล่องคุณจะไม่สามารถเรียกคืนคุกกี้ได้จากช่องนี้
Alexis Dufrenoy

1
@Traroth: แต่ฉันสามารถใส่คุกกี้ใหม่ได้ ฉันแค่ค้นหาคำอธิบายประกอบที่สะดวก แต่ก็สามารถทำได้ด้วยมือแน่นอน
Weekens

8
ความคิดเห็นอย่างรวดเร็ว: เป็นไปได้อย่างสมบูรณ์ในทางเทคนิคในการมี setter ที่ใช้ (แม้จะเป็นแบบส่วนตัวที่ตรวจพบโดยอัตโนมัติ) และเพียงละเว้นการเข้าถึง (ไม่มีฟิลด์สาธารณะหรือทะเยอทะยาน) นอกจากนี้ยังเป็นไปได้ที่จะเพิ่ม@JsonIgnoreในทะเยอทะยาน แต่@JsonPropertyใน setter ซึ่งในกรณีที่สิ่งที่ไม่ต่อเนื่อง แต่สามารถ deserialized
StaxMan

4
คุณจะยอมรับคำตอบสำหรับคำถามนี้หรือไม่? (สองสามคนของคุณอายุไม่กี่ปีและยังไม่ได้รับการยอมรับด้วย ... โปรดพิจารณาการตรวจสอบ!) :) การเปิดเผยอย่างสมบูรณ์ - ฉันไม่มีคำตอบสำหรับคำถามเหล่านี้
Barett

คำตอบ:


187

@JsonIgnoreคุณสามารถทำเครื่องหมายว่า

ด้วย 1.9 คุณสามารถเพิ่ม@JsonIgnoregetter @JsonPropertyสำหรับ setter เพื่อทำให้ deserialize แต่ไม่ทำให้เป็นอนุกรม


6
@JsonIgnore ช่วยป้องกันการดีซีเรียลไลเซชันเช่นกัน สำหรับชั่วคราว - ฉันจะตรวจสอบมัน
Weekens

98
ด้วย 1.9 คุณสามารถเพิ่ม@JsonIgnoregetter @JsonPropertyสำหรับ setter เพื่อทำให้ deserialize แต่ไม่ทำให้เป็นอนุกรม
StaxMan

ความคิดเห็นของ StaxMan ควรเป็นคำตอบใช่มั้ย ทำไมถึงยังเป็นคอมเม้นท์ ... ! .. ?
Saravanabalagi Ramachandran

ดูเหมือนว่างานชั่วคราวสำหรับฉันฉันทำเครื่องหมายฟิลด์ "ชั่วคราว" ที่ฉันไม่ต้องการให้เป็น serilized / deserialized
rohith

คำตอบก่อนหน้านี้ที่แนะนำให้ใช้transient(เหมือนในprivate transient String password;) แต่ฟิลด์ชั่วคราวที่มี public getters จะถูกละเว้นหากMapperFeature.PROPAGATE_TRANSIENT_MARKERเปิดใช้งานอยู่
ทอม

96

แสดงให้เห็นถึงสิ่งที่ StaxMan ระบุไว้สิ่งนี้ใช้ได้กับฉัน

private String password;

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

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

12
คุณพึ่งพา Json ใดบ้าง สิ่งนี้ใช้ไม่ได้กับ com.fasterxml.jackson
Alexander Burakevych

3
ขอบคุณ! @JsonIgnoreไม่จำเป็นต้องอยู่บนสนามดูเหมือนว่า
Ferran Maylinch

com.fasterxml.jackson.annotation.JsonIgnore จาก jackson-annotations- <version> .jar
mvmn

ฉันได้ลองแล้วและมันก็ไม่ได้ผลสำหรับฉัน ฉันใช้ v2.8 ความช่วยเหลือใด ๆ
Maz

36

วิธีง่าย ๆ คือการใส่คำอธิบายประกอบใน getters และ setters ของคุณ

นี่คือตัวอย่างดั้งเดิมที่ได้รับการแก้ไขเพื่อแยกรหัสผ่านข้อความล้วน แต่จากนั้นใส่คำอธิบายวิธีการใหม่ที่เพิ่งส่งคืนฟิลด์รหัสผ่านเป็นข้อความที่เข้ารหัส

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

เริ่มต้นด้วยJackson 2.6สามารถทำเครื่องหมายคุณสมบัติเป็นแบบอ่านหรือเขียนอย่างเดียวได้ มันง่ายกว่าแฮ็คคำอธิบายประกอบบนอุปกรณ์เสริมและเก็บข้อมูลทั้งหมดไว้ในที่เดียว:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}

นี่เป็นทางออกที่ยอดเยี่ยมเรียบง่ายใช้งานได้ ขอบคุณ
dhqvinh

17

นอกจาก@JsonIgnoreนั้นยังมีความเป็นไปได้อื่น ๆ อีกสองอย่าง:

  • ใช้JSON Viewsเพื่อกรองฟิลด์ตามเงื่อนไข (โดยค่าเริ่มต้นไม่ได้ใช้สำหรับการดีซีเรียลไลซ์เซชั่นใน 2.0 จะพร้อมใช้งาน แต่คุณสามารถใช้มุมมองที่แตกต่างกันในการทำให้เป็นอนุกรมการดีซีเรียลไลเซชัน)
  • @JsonIgnoreProperties ในชั้นเรียนอาจมีประโยชน์

10

transientเป็นทางออกสำหรับฉัน ขอบคุณ! เป็นภาษาของ Java และหลีกเลี่ยงการเพิ่มหมายเหตุประกอบเฉพาะของกรอบงานอื่น


2
หากคุณลักษณะของคุณไม่ได้ใช้ ORM ที่เกี่ยวข้องเช่น ... พบว่า @JsonIgnore น่าสนใจยิ่งกว่าในกรณีของฉันแม้ว่าฉันจะถูกขังอยู่ที่แจ็คสัน แต่มันเป็นการแลกเปลี่ยนที่ดี
Joao Pereira

3
คุณไม่จำเป็นต้องล็อคแจ็คสันหากคุณสร้างคำอธิบายประกอบของคุณเองและให้คำอธิบายประกอบโดย JsonIgnore และ JacksonAnnotationsInside ด้วยวิธีนี้หากคุณเปลี่ยน serializers คุณจะต้องเปลี่ยนคำอธิบายประกอบของคุณเอง
DavidA

4

หนึ่งควรถามว่าทำไมคุณต้องการวิธี getter สาธารณะสำหรับรหัสผ่าน ไฮเบอร์เนตหรือกรอบ ORM อื่น ๆ จะทำอย่างไรกับวิธีทะเยอทะยานส่วนตัว สำหรับการตรวจสอบว่ารหัสผ่านถูกต้องคุณสามารถใช้

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}

ฉันคิดว่านี่เป็นวิธีที่ดีที่สุดในการคิดถึงวิธีแก้ปัญหา มันสมเหตุสมผลกว่าที่จะทำให้สิ่งที่คุณต้องการเป็นส่วนตัวและควบคุมสิ่งเหล่านั้นจากวัตถุนั้น
arcynum

2

Jackson มีคลาสชื่อว่า SimpleBeanPropertyFilter ที่ช่วยกรองฟิลด์ระหว่างการทำให้เป็นอนุกรมและการดีซีเรียลไลเซชัน ไม่ใช่ทั่วโลก ฉันคิดว่านั่นคือสิ่งที่คุณต้องการ

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

    //setter, getter..
}

จากนั้นในรหัสของคุณ:

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

สิ่งนี้จะป้องกันไม่ให้passwordฟิลด์รับต่อเนื่อง นอกจากนี้คุณจะสามารถยกเลิกการซีเรียลpasswordฟิลด์ตามที่เป็น เพียงตรวจสอบให้แน่ใจว่าไม่มีการใช้ตัวกรองกับวัตถุ ObjectMapper

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

0

ตั้งค่าตัวแปรเป็น

@JsonIgnore

สิ่งนี้ยอมให้ตัวแปรถูกข้ามโดย json serializer

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