Alexander Nikolaev
Alexander Nikolaev

Reputation: 45

Jackson and multiple interface inheritance

I'm trying to implement json serialization of the single entity to different views according to used interface. For example we have:

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 implementation always returns Book class (with unused fields set to null). To serialize interfaces I tried to use annotation @JsonSerialize(as = Interface.class) for each, but for all interfaces jackson always use only the first one listed in 'implements' expression. Is there a way to configure jackson like I need? Or may be there is a better solution?

Upvotes: 2

Views: 2561

Answers (1)

jFrenetic
jFrenetic

Reputation: 5542

Seems like you have 2 options:

  1. Write a custom Jackson Serializer
  2. Use Jackson views, which looks like a more viable choice (full documentation could be found here).

With Views it could be implemented in 3 easy steps:

  1. Define your view markers:

BookViews.java:

public class BookViews {

    public static class BookBrief { }

    public static class BookPreview { }

}
  1. Annotate which Book fields you want to be exposed in each view:

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. Annotate REST method with JSonValue and specify which view you want to use:

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

}

Result:

GET http://localhost:8080/root/rest/books/all:

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

GET http://localhost:8080/root/rest/books/previews:

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

Upvotes: 3

Related Questions