Làm cách nào để yêu cầu jackson bỏ qua thuộc tính mà tôi không có quyền kiểm soát mã nguồn?


112

Một câu chuyện ngắn, một trong những thực thể của tôi có GeometryCollection đưa ra một ngoại lệ khi bạn gọi "getBoundary" (lý do tại sao của đây là một cuốn sách khác, bây giờ hãy nói rằng đây là cách nó hoạt động).

Có cách nào tôi có thể nói với Jackson để không bao gồm cửa sổ cụ thể đó không? Tôi biết mình có thể sử dụng @JacksonIgnore khi sở hữu / kiểm soát mã. Nhưng đây không phải là trường hợp, jackson kết thúc đạt đến điểm này thông qua việc tuần tự hóa liên tục các đối tượng mẹ. Tôi đã thấy một tùy chọn lọc trong tài liệu jackson. Đó có phải là một giải pháp hợp lý?

Cảm ơn!

Câu trả lời:


168

Bạn có thể sử dụng Jackson Mixins . Ví dụ:

class YourClass {
  public int ignoreThis() { return 0; }    
}

Với Mixin này

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

Với cái này:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

Biên tập:

Nhờ các nhận xét, với Jackson 2.5+, API đã thay đổi và nên được gọi bằng objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
Và nếu thuộc tính do máy tạo ra và có các ký tự không được hỗ trợ trong tên của nó? Giống '@'? JVM cho phép nó, nhưng trình biên dịch Java thì không. Jackson có giải pháp cho việc này không?
đánh dấu

3
Và trong jackson 2.2 đó làobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Làm cách nào để bỏ qua bằng cách chỉ định tên thuộc tính thay vì getter?
Erran Morad

68

Một khả năng khác là, nếu bạn muốn bỏ qua tất cả các thuộc tính chưa biết, bạn có thể định cấu hình trình ánh xạ như sau:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
Sẽ thật tuyệt nếu chúng ta có thể cấu hình objectMapper để chỉ bỏ qua các thuộc tính specifc. tức là báo cáo ngoại lệ cho tất cả các trường mới / không xác định ngoại trừ cho phép nói 'myfield'. Một cái gì đó giống nhưmapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

Lưu ý rằng điều này cũng có thể được định cấu hình trên một đầu đọc bằng cách sử dụng without()như trong:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens

Tôi thực sự khuyên bạn không nên sử dụng cơ chế này. Tư duy "nghiêm khắc" ở Jackson, gây ra lỗi phát sinh trên các trường không xác định / không được xử lý là một trong những điểm mạnh của nó và phù hợp với bản chất được định kiểu tĩnh / biên dịch theo thời gian phân tích của Java. Thay vào đó, tốt hơn là chọn không xử lý một tập hợp các trường bị bỏ qua nhất định.
Per Lundberg

26

Sử dụng lớp Java

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

Sử dụng chú thích

@JsonIgnoreProperties(ignoreUnknown=true)

11

Cách tiếp cận dựa trên chú thích tốt hơn. Nhưng đôi khi thao tác thủ công là cần thiết. Với mục đích này, bạn có thể sử dụng mà không có phương thức của ObjectWriter .

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

9
Cách tiếp cận này không hiệu quả với tôi, nhưng cách mixin thì có. Tôi vẫn nhận được các thuộc tính bị bỏ qua sau khi tuần tự hóa. Tại sao chúng ta có mixin trong khi chúng ta không cóAttribute ()?
Erran Morad

9

Các chú thích kết hợp hoạt động khá tốt ở đây như đã được đề cập. Một khả năng khác ngoài mỗi thuộc tính @JsonIgnore là sử dụng @JsonIgnoreType nếu bạn có một loại không bao giờ được đưa vào (tức là nếu tất cả các trường hợp của thuộc tính GeometryCollection nên bị bỏ qua). Sau đó, bạn có thể thêm nó trực tiếp (nếu bạn kiểm soát loại) hoặc sử dụng kết hợp, như:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

Điều này có thể thuận tiện hơn nếu bạn có rất nhiều lớp mà tất cả đều có một trình truy cập 'ignoreredType getContext ()' duy nhất hoặc tương tự (đây là trường hợp của nhiều khung)


5

Tôi đã gặp vấn đề tương tự, nhưng nó liên quan đến các mối quan hệ hai chiều của Hibernate. Tôi muốn thể hiện một mặt của mối quan hệ và lập trình bỏ qua mặt kia, tùy thuộc vào quan điểm mà tôi đang xử lý. Nếu bạn không thể làm điều đó, bạn sẽ kết thúc với những điều khó chịu StackOverflowException. Ví dụ, nếu tôi có những đồ vật này

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

Tôi muốn lập trình bỏ qua parenttrường ở B nếu tôi đang nhìn A và bỏ qua childrentrường trong A nếu tôi đang nhìn B.

Tôi đã bắt đầu sử dụng mixin để làm điều này, nhưng điều đó rất nhanh chóng trở nên kinh khủng; bạn có rất nhiều lớp vô dụng nằm xung quanh chỉ tồn tại để định dạng dữ liệu. Cuối cùng, tôi đã viết bộ tuần tự của riêng mình để xử lý vấn đề này theo cách gọn gàng hơn: https://github.com/monitorjbl/json-view .

Nó cho phép bạn chỉ định theo chương trình những trường nào cần bỏ qua:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

Nó cũng cho phép bạn dễ dàng chỉ định các chế độ xem rất đơn giản thông qua trình đối sánh ký tự đại diện:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

Trong trường hợp ban đầu của tôi, nhu cầu về các chế độ xem đơn giản như thế này là thể hiện mức tối thiểu nhất về cha / con, nhưng nó cũng trở nên hữu ích cho bảo mật dựa trên vai trò của chúng tôi. Chế độ xem ít đặc quyền của các đối tượng cần thiết để trả về ít thông tin hơn về đối tượng.

Tất cả những điều này đến từ bộ tuần tự, nhưng tôi đã sử dụng Spring MVC trong ứng dụng của mình. Để giúp nó xử lý đúng các trường hợp này, tôi đã viết một tích hợp mà bạn có thể đưa vào các lớp Spring controller hiện có:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

Cả hai đều có sẵn trên Maven Central. Tôi hy vọng nó sẽ giúp được ai đó ngoài kia, đây là một vấn đề đặc biệt xấu với Jackson mà không có giải pháp tốt cho trường hợp của tôi.


Nhập khẩu để làm Match.match()gì?
Pasupathi Rajamanickam

2

Nếu bạn LUÔN LUÔN loại trừ các thuộc tính nhất định cho bất kỳ lớp nào, bạn có thể sử dụng setMixInResolverphương pháp:

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });

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.