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 个选择:
- 编写自定义 Jackson Serializer
- 使用 Jackson 视图,这看起来是一个更可行的选择(可以找到完整的文档 here)。
使用 Views 只需 3 个简单步骤即可实现:
- 定义您的视图标记:
BookViews.java:
public class BookViews {
public static class BookBrief { }
public static class BookPreview { }
}
- 注释您希望在每个视图中显示哪些 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
}
- 用 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
}
]
我正在尝试根据使用的界面实现 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 个选择:
- 编写自定义 Jackson Serializer
- 使用 Jackson 视图,这看起来是一个更可行的选择(可以找到完整的文档 here)。
使用 Views 只需 3 个简单步骤即可实现:
- 定义您的视图标记:
BookViews.java:
public class BookViews {
public static class BookBrief { }
public static class BookPreview { }
}
- 注释您希望在每个视图中显示哪些 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
}
- 用 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
}
]