Chỉ sử dụng @JsonIgnore trong quá trình tuần tự hóa, nhưng không khử lưu huỳnh


324

Tôi có một đối tượng người dùng được gửi đến và từ máy chủ. Khi tôi gửi đối tượng người dùng, tôi không muốn gửi mật khẩu băm cho khách hàng. Vì vậy, tôi đã thêm @JsonIgnorevào thuộc tính mật khẩu, nhưng điều này cũng ngăn không cho nó được khử lưu vào mật khẩu khiến người dùng khó đăng ký khi họ không có mật khẩu.

Làm thế nào tôi chỉ có @JsonIgnorethể áp dụng để tuần tự hóa và không khử lưu huỳnh? Tôi đang sử dụng Spring JSONView, vì vậy tôi không có nhiều quyền kiểm soát ObjectMapper.

Những điều tôi đã thử:

  1. Thêm @JsonIgnorevào tài sản
  2. Chỉ thêm @JsonIgnorevào phương thức getter

Câu trả lời:


480

Chính xác làm thế nào để làm điều này phụ thuộc vào phiên bản Jackson mà bạn đang sử dụng. Điều này đã thay đổi xung quanh phiên bản 1.9 , trước đó, bạn có thể làm điều này bằng cách thêm @JsonIgnorevào getter.

Mà bạn đã thử:

Chỉ thêm @JsonIgnore vào phương thức getter

Thực hiện điều này và cũng thêm một @JsonPropertychú thích cụ thể cho tên trường "mật khẩu" JSON của bạn vào phương thức setter cho mật khẩu trên đối tượng của bạn.

Các phiên bản gần đây hơn của Jackson đã thêm READ_ONLYWRITE_ONLYchú thích các đối số cho JsonProperty. Vì vậy, bạn cũng có thể làm một cái gì đó như:

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

Tài liệu có thể được tìm thấy ở đây .


2
gist.github.com/thurloat/2510887 cho Jackson JSON bỏ qua trên deserialize chỉ
Hadas

1
AFAIK bạn vẫn phải thực hiện setter và chú thích nó. Tôi chỉ muốn các getter cho serialization. Tạm thời bạn nói về cái gì? Đó là một chú thích của JPA AFAIK
Matt Broekhuis

3
Ngoài ra, hãy đảm bảo xóa @JsonProperty khỏi trường nếu không nó sẽ ghi đè các chú thích getter / setter của bạn
Anton Soradoi 4/03/2015

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

1
Jackson-annotations 2.5 không có tính năng sau này. Jackson-annotations 2.6.3 hiện
radiantRazor

98

Để thực hiện điều này, tất cả những gì chúng ta cần là hai chú thích:

  1. @JsonIgnore
  2. @JsonProperty

Sử dụng @JsonIgnoretrên thành viên lớp và getter của nó, và @JsonPropertytrên setter của nó. Một minh họa mẫu sẽ giúp làm điều này:

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
đó là điều duy nhất phù hợp với tôi với jackson 2.6.4. Tôi đã cố gắng hết sức để sử dụng @JsonProperty (access = Access.WRITE_ONLY) nhưng nó không hoạt động với tôi.
cirovladimir

76

Kể từ phiên bản 2.6: một cách trực quan hơn là sử dụng com.fasterxml.jackson.annotation.JsonPropertychú thích trên trường:

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

Ngay cả khi một getter tồn tại, giá trị trường được loại trừ khỏi tuần tự hóa.

JavaDoc nói:

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

Trong trường hợp bạn cần nó theo cách khác, chỉ cần sử dụng Access.READ_ONLY.


1
Tôi không hiểu tại sao có quá ít sự ủng hộ, đây là cách thanh lịch để giải quyết vấn đề này, hoạt động như một cơ duyên. Không cần chú thích getter, setter và trường. Chỉ có lĩnh vực. Cảm ơn.
CROSP

Bản này có sẵn từ phiên bản 2.6, xem quickxml.github.io/jackson-annotations/javadoc/2.6/com/ Kẻ
Bia Daniel

Có lẽ là câu trả lời tốt nhất cho hơn 2,6 người dùng.
David Dossot

Hãy chắc chắn rằng bạn không sử dụng nhập org.codehaus.jackson.annotate . Giải pháp @ DanielBERer hoạt động cho Jackson 2.6.3. Đây phải là câu trả lời được chấp nhận ngay bây giờ khi Jackson đã được cập nhật.
Kent Bull

13

Trong trường hợp của tôi, tôi có Jackson tự động (de) tuần tự hóa các đối tượng mà tôi trả về từ bộ điều khiển Spring MVC (Tôi đang sử dụng @RestContoder với Spring 4.1.6). Tôi đã phải sử dụng com.fasterxml.jackson.annotation.JsonIgnorethay vì org.codehaus.jackson.annotate.JsonIgnore, như cách khác, nó chỉ đơn giản là không làm gì cả.


1
đây là một câu trả lời cực kỳ hữu ích thực sự giúp tôi tìm ra nguồn gốc tại sao @JsonIgnore không được Jackson tôn vinh ... cảm ơn!
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
Nó có thể giúp trong tương lai để đưa ra một mô tả ngắn gọn về cách thức hoạt động của mã.
KWILLIAM

Ổn thỏa !! Bạn đang cố gắng gì ở đây? Nhận được nhiều phiếu hơn? lol
Balaji Boggaram Ramanarayan

0

Một cách dễ dàng khác để xử lý việc này là sử dụng đối số allowSetters=true trong chú thích. Điều này sẽ cho phép mật khẩu được giải tuần tự hóa vào dto của bạn nhưng nó sẽ không tuần tự hóa nó thành một cơ quan phản hồi có sử dụng đối tượng chứa.

thí dụ:

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

Cả hai foobarđược điền vào đối tượng, nhưng chỉ foo được viết vào một cơ thể phản hồi.


Chỉnh sửa câu trả lời của bạn với đoạn mã làm việc.
dkb

Đó là sai lầm của tôi, tôi không nhận ra bạn đã sửa đoạn trích. Nhìn vào những thay đổi của bạn, có vẻ như những năm viết của tôi bằng Groovy đã cho tôi và bản dịch sang Java của tôi hơi khó hiểu. Lấy làm tiếc!
Dhandley
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.