Jackson 和多接口继承

Jackson and multiple interface inheritance

我正在尝试根据使用的界面实现 json 单个实体到不同视图的序列化。 例如我们有:

public interface BookBrief {
  long getId();
  String getTitle();
}

public interface BookPreview {
  long getId();
  String getAnnotation();
}

public class Book implements BookBrief, BookPreview {

  // class fields here

  public long getId() {...}

  public String getTitle() {...}

  public String getText() {...}

  public String getAnnotation() {...}

  // setters here
}


// service which results is serialized to json in Spring MVC controllers

public interface BookService {

  List<? extends BookBrief> getBooks();

  BookPreview getBookPreview(long id);

  Book getBook(long id);
}

BookService 实现总是 returns Book class(未使用的字段设置为空)。 为了序列化接口,我尝试为每个接口使用注释 @JsonSerialize(as = Interface.class) , 但对于所有接口,杰克逊始终只使用 'implements' 表达式中列出的第一个接口。 有没有办法像我需要的那样配置杰克逊?或者可能有更好的解决方案?

您似乎有 2 个选择:

  1. 编写自定义 Jackson Serializer
  2. 使用 Jackson 视图,这看起来是一个更可行的选择(可以找到完整的文档 here)。

使用 Views 只需 3 个简单步骤即可实现:

  1. 定义您的视图标记:

BookViews.java:

public class BookViews {

    public static class BookBrief { }

    public static class BookPreview { }

}
  1. 注释您希望在每个视图中显示哪些 Book 字段:

Book.java:

public class Book {

    @JsonView({BookViews.BookBrief.class, BookViews.BookPreview.class})
    private long id;

    @JsonView(BookViews.BookBrief.class)
    private String title;

    @JsonView(BookViews.BookPreview.class)
    private String annotation;

    // Constructors and getters/setters
}
  1. 用 JSonValue 注释 REST 方法并指定要使用的视图:

BookService.java:

@Path("books")
public class BookService {

    private static final List<Book> library = Arrays.asList(
            new Book(1, "War and Peace", "Novel"),
            new Book(2, "A Game of Thrones", "Fantasy")
    );

    @GET
    @Path("all")
    @JsonView(BookViews.BookBrief.class)
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBooks() {
        return Response.status(Response.Status.OK).entity(library).build();
    }

    @GET
    @Path("previews")
    @JsonView(BookViews.BookPreview.class)
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBookPreviews() {
        return Response.status(Response.Status.OK).entity(library).build();
    }

}

结果:

获取http://localhost:8080/root/rest/books/all:

[
    {
        "id": 1,
        "title": "War and Peace"
    },
    {
        "id": 2,
        "title": "A Game of Thrones"
    }
]

获取 http://localhost:8080/root/rest/books/previews:

[
    {
        "annotation": "Novel",
        "id": 1
    },
    {
        "annotation": "Fantasy",
        "id": 2
    }
]