Jackson: làm thế nào để ngăn chặn tuần tự hóa trường


163

Tôi có một lớp thực thể với trường mật khẩu:

class User {
    private String password;

    //setter, getter..
}

Tôi muốn lĩnh vực này được bỏ qua trong quá trình tuần tự hóa. Nhưng nó vẫn có thể DEserialize. Điều này là cần thiết, để khách hàng có thể gửi cho tôi một mật khẩu mới, nhưng không thể đọc được mật khẩu hiện tại.

Làm thế nào để tôi thực hiện điều này với Jackson?


1
Bạn không muốn tuần tự hóa nó, nhưng bạn muốn có thể giải tuần tự hóa nó? Điều đó là không thể, tôi sẽ nói. Nếu bạn không đặt cookie vào hộp, bạn sẽ không thể truy xuất cookie từ hộp này.
Alexis Dufrenoy

1
@Traroth: nhưng tôi có thể đặt cookie MỚI. Tôi chỉ đang tìm kiếm một chú thích thuận tiện, nhưng điều này chắc chắn có thể được thực hiện bằng tay.
tuần

8
Nhận xét nhanh: về mặt kỹ thuật, hoàn toàn có thể sử dụng một setter được sử dụng (ngay cả những cái riêng tư được tự động phát hiện) và chỉ cần bỏ qua bộ truy cập (không có trường công khai hoặc getter). Cũng có thể thêm @JsonIgnorevào getter, nhưng @JsonPropertytrên setter, trong trường hợp đó mọi thứ không được tuần tự hóa, nhưng có thể được giải tuần tự hóa.
StaxMan

4
Bạn có phiền khi chấp nhận một câu trả lời cho câu hỏi này? (Một vài người khác của bạn đã vài tuổi và vẫn chưa được chấp nhận ... Vui lòng xem xét đánh giá!) :) Tiết lộ đầy đủ - Tôi không có câu trả lời cho bất kỳ câu hỏi nào trong số này.
Barett

Câu trả lời:


187

Bạn có thể đánh dấu nó là @JsonIgnore.

Với 1.9, bạn có thể thêm @JsonIgnorecho getter, @JsonPropertycho setter, để làm cho nó được giải tuần tự hóa nhưng không tuần tự hóa.


6
@JsonIgnore cũng ngăn chặn quá trình khử lưu huỳnh. Để thoáng qua - tôi sẽ kiểm tra nó.
tuần

98
Với 1.9, bạn có thể thêm @JsonIgnorecho getter, @JsonPropertycho setter, để làm cho nó được giải tuần tự hóa nhưng không tuần tự hóa.
StaxMan

Nhận xét của StaxMan phải là câu trả lời, phải không? Tại sao nó vẫn là một bình luận sau đó ...! ..?
Saravanabalagi Ramachandran

thoáng qua dường như không làm việc cho tôi, tôi đã đánh dấu trường "thoáng qua" mà tôi không muốn nó được serilized / deserialized.
ngày

Câu trả lời này trước đây được đề xuất bằng cách sử dụng transient(như trong private transient String password;) nhưng các trường tạm thời với getters công cộng bị bỏ qua trừ khi MapperFeature.PROPAGATE_TRANSIENT_MARKER được bật.
tom

96

Minh họa những gì StaxMan đã nêu, điều này hiệu quả với tôi

private String password;

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

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

12
Bạn sử dụng phụ thuộc Json nào? Điều này không hoạt động với com.fasterxml.jackson
Alexander Burakevych

3
Cảm ơn! @JsonIgnoredường như không cần thiết trên sân
Ferran Maylinch

com.fasterxml.jackson.annotation.JsonIgnore từ jackson-annotations- <phiên bản> .jar
mvmn

Tôi đã thử điều này và nó không làm việc cho tôi. Tôi sử dụng v2.8. Có ai giúp đỡ không?
Maz

36

Cách dễ dàng là chú thích getters và setters của bạn.

Dưới đây là ví dụ ban đầu được sửa đổi để loại trừ mật khẩu văn bản đơn giản, nhưng sau đó chú thích một phương thức mới chỉ trả về trường mật khẩu dưới dạng văn bản được mã hóa.

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

Bắt đầu với Jackson 2.6 , một tài sản có thể được đánh dấu là chỉ đọc hoặc viết. Nó đơn giản hơn việc hack các chú thích trên cả hai bộ truy cập và giữ tất cả thông tin ở một nơi:

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

Đây là một giải pháp tuyệt vời, đơn giản, làm việc. Cảm ơn.
dhqvinh

17

Ngoài ra @JsonIgnore, có một vài khả năng khác:

  • Sử dụng Chế độ xem JSON để lọc ra các trường một cách có điều kiện (theo mặc định, không được sử dụng để giải tuần tự hóa, trong 2.0 sẽ có sẵn nhưng bạn có thể sử dụng chế độ xem khác nhau về tuần tự hóa, giải tuần tự hóa)
  • @JsonIgnoreProperties trên lớp có thể hữu ích

10

transientlà giải pháp cho tôi. cảm ơn! nó có nguồn gốc từ Java và tránh cho bạn thêm một chú thích cụ thể theo khung khác.


2
Điều đó hoạt động nếu thuộc tính của bạn thực sự thoáng qua, không liên quan đến ORM, chẳng hạn .... Tìm thấy @JsonIgnore thú vị hơn trong trường hợp của tôi, mặc dù tôi sẽ bị khóa với jackson, nhưng đó là một sự đánh đổi tốt
Joao Pereira

3
Bạn không cần phải bị khóa với jackson nếu bạn tạo chú thích của riêng mình và được chú thích bởi JsonIgnore và JacksonAnnotationsInside. Bằng cách đó, nếu bạn thay đổi serial serial, bạn chỉ phải thay đổi chú thích của riêng bạn.
DavidA

4

Bạn nên hỏi tại sao bạn muốn một phương thức getter công khai cho mật khẩu. Hibernate, hoặc bất kỳ khung ORM nào khác, sẽ thực hiện với phương thức getter riêng. Để kiểm tra xem mật khẩu có đúng không, bạn có thể sử dụng

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

Tôi thực sự nghĩ rằng đây là cách tốt nhất để suy nghĩ về giải pháp. Nó có ý nghĩa hơn để làm cho những thứ bạn cần riêng tư và kiểm soát chúng từ chính đối tượng.
arcynum

2

Jackson có một lớp có tên SimpleBeanPropertyFilter giúp lọc các trường trong quá trình tuần tự hóa và giải tuần tự hóa; không phải trên toàn cầu Tôi nghĩ đó là những gì bạn muốn.

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

    //setter, getter..
}

Sau đó, trong mã của bạn:

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

Điều này sẽ ngăn passwordtrường để được nối tiếp. Ngoài ra, bạn sẽ có thể khử lưu lượng passwordcác trường như nó là. Chỉ cần đảm bảo không có bộ lọc nào được áp dụng trên đối tượng ObjectMapper.

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

0

đặt biến là

@JsonIgnore

Điều này cho phép biến bị bỏ qua bởi json serializer

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.