Asymmetric serialization and deserialization using Jackson
I am using Jackson to serialize and deserialize data for a RESTful API. I would like to have a REST ( /comments
) resource that allows POST comments as well as a list of comments.
Here's a (simplified) example of what is being sent to /comments
.
{"text":"Text","author":"Paul","email":"paul@example.org"}
Here's what the result GET /comments
should look like:
[{"text":"Text","author":"Paul","emailHash":"76w0kjKP9HpsdhBjx895Sg=="}]
Since the email addresses shouldn't be visible to anyone, I decided to return only the MD5 hash of the email addresses in the response.
I created a simple class is a POJO Comment
, which has fields with getters and setters for text
, author
, email
and emailHash
.
Now, when I serialize the result, I get this:
[{"text":"Text","author":"Paul","email":null,"emailHash":"76w0kjKP9HpsdhBjx895Sg=="}]
But I really don't like email
to return as quality null
here. It rather shouldn't be included at all.
Using annotation @JsonIgnore
in this field will also ignore it on deserialization. Should I create two classes, for example CreationComment
, and ResultComment
a superclass Comment
, which has a general field, or is there a way that avoids creating additional classes?
source to share
You don't need to create 2 classes at all. With Jackson, you have complete control over the behavior of the property during serialization and deserialization with annotations, when @JsonIgnore
in the getter you disable serialization of the property in your Json response and use the annotation @JsonProperty
in the setter, the property will be during deserialization. The code will look like this:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Comment {
private String author;
private String email;
@JsonIgnore
public String getEmail() {
return email;
}
@JsonProperty
public void setEmail(String email) {
this.email = email;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Comment comment = new Comment();
comment.setAuthor("anAuthor");
comment.setEmail("email@example.com");
try {
System.out.println(objectMapper.writeValueAsString(comment));
String json = "{\"author\":\"anAuthor\",\"email\":\"another@email.com\"}";
Comment fromJson = objectMapper.readValue(json, Comment.class);
System.out.println("Result from Json: author= " + fromJson.getAuthor() + ", email= " + fromJson.getEmail());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Exit after running the method main()
to test the solution:
{"author":"anAuthor"}
Result from Json: author= anAuthor, email= another@email.com
Hope it helps,
Jose Luis
source to share
You can put @JsonIgnore
on getEmail
to prevent it from being serialized to JSON and use @JsonCreator
it to tell Jackson to the constructor to use for deserialization. The constructor will then only accept the property email
and will hash and assign your field emailHash
.
You can put annotation @JsonInclude
in your class Comment
to prevent serialization of fields null
.
Your class probably ends up looking something like this:
@JsonInclude(Include.NON_NULL)
public class Comment {
private final String email;
private final String emailHash;
@JsonCreator
public Comment(@JsonProperty("email") String email) {
this.email = email;
this.emailHash = MD5.hash(email);
}
@JsonIgnore
public String getEmail() {
return email;
}
public String getEmailHash() {
return emailHash;
}
}
source to share