Serializing and Deserializing a Card with Jersey and Jackson
I have one Pojo object that is serialized to Jersey using jackson:
public class BookOfFriendsAnswer {
private Map<String, List<BookSummary>> books;
public BookOfFriendsAnswer() {
}
public BookOfFriendsAnswer(Map<String, List<BookSummary>> books) {
this.books = books;
}
public Map<String, List<BookSummary>> getBooks() {
return books;
}
public void setBooks(Map<String, List<BookSummary>> books) {
this.books = books;
}
}
Serialization creates a JSon like this:
{
"books": {
"entry": [
{
"key": "54567bbce4b0e0ef9379993e",
"value": "BookSummary{id='54567bbde4b0e0ef9379993f', title='title 1', authors=[Steve,James] } BookSummary{id='54567bd9e4b0e0ef93799940', title='Title 2', authors=[Simon, Austin]}"
}
]
}
}
However, when I try to deserialize a message from my client like this:
mapper.readValue(json, clazz)
I am getting the following error:
Unrecognized field "key" (class com.example.server.api.BookSummary), not marked as clueless
I don't know if the problem is from the server generated JSOn or client side deserialization.
Do you know what the problem is and how to fix it?
Thank you so much
source to share
So after a little testing with:
- Jersey 1.18.1 (with support
jersey-json-1.18.1
for JSON support) - Jersey 2.13 (with support
jersey-media-json-jackson-2.13
for JSON support) - Jersey 2.13 (with support
jersey-media-moxy-2.13
for JSON support)
The last test (jersey-media-moxy-2.13) was the only one able to get this exact output
{
"books": {
"entry": [
{
"key": "54567bbce4b0e0ef9379993e",
"value": "BookSummary{id='54567bbde4b0e0ef9379993f', title='title 1', authors=[Steve,James] } BookSummary{id='54567bd9e4b0e0ef93799940', title='Title 2', authors=[Simon, Austin]}"
}
]
}
}
Having said that, I will make the assumption that you are using Jersey 2.x version. I'm not sure if there is any configuration in MOXy to better support this use case, but to keep things simple, just add the following dependency and get rid of MOXy
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey-version}</version>
</dependency>
With this you will get the correct JSON output
{ // BookOfFriendsAnswer object
"books": { // Map<String, List<BookSummary>> books
"randomKey": [ // String (key) , List<BookSummary> (value)
{ // BookSummary object
"id": "54567bbde4b0e0ef9379993f",
"title": "Title 1",
"authors": ["Steve", "James"]
}
]
}
}
Simple test
Resource Method
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getResponse() {
BookOfFriendsAnswer books = new BookOfFriendsAnswer();
String id = "randomKey"; <===== Not sure if you want the key to be
the BookSummary id
BookSummary summary = new BookSummary();
summary.setId(id);
summary.setTitle("Title 1");
summary.getAuthors().add("Steve");
summary.getAuthors().add("James");
List<BookSummary> summaries = new ArrayList<>();
summaries.add(summary);
books.getBooks().put("randomKey", summaries);
return Response.ok(books).build();
}
Test with ObjectMapper
@Test
public void testGetIt() throws Exception {
String responseMsg = target.path("book").request().get(String.class);
ObjectMapper mapper = new ObjectMapper();
BookOfFriendsAnswer books = mapper.readValue(
responseMsg, BookOfFriendsAnswer.class);
System.out.println(books);
}
Test without ObjectMapper - using auto-configured Jackson provider
@Test
public void testGetIt() throws Exception {
BookOfFriendsAnswer responseMsg
= target.path("book").request().get(BookOfFriendsAnswer.class);
System.out.println(responseMsg);
}
source to share
I think you should create a specific type of card and provide it during the deserialization process:
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, ArrayList.class);
HashMap<String, List<BookSummary>> map = mapper.readValue(json, mapType);
source to share