Different names of JSON property during serialization and deserialization
Is it possible: to have one field in class, but different names for it during serialization/deserialization in Jackson library?
For example, I have class "Coordiantes".
class Coordinates{
int red;
}
For deserialization from JSON want to have format like this:
{
"red":12
}
But when I will serialize object, result should be like this one:
{
"r":12
}
I tried to implement this by applying @JsonProperty
annotation both on getter and setter (with different values):
class Coordiantes{
int red;
@JsonProperty("r")
public byte getRed() {
return red;
}
@JsonProperty("red")
public void setRed(byte red) {
this.red = red;
}
}
but I got an exception:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "red"
Just tested and this works:
public class Coordinates {
byte red;
@JsonProperty("r")
public byte getR() {
return red;
}
@JsonProperty("red")
public void setRed(byte red) {
this.red = red;
}
}
The idea is that method names should be different, so jackson parses it as different fields, not as one field.
Here is test code:
Coordinates c = new Coordinates();
c.setRed((byte) 5);
ObjectMapper mapper = new ObjectMapper();
System.out.println("Serialization: " + mapper.writeValueAsString(c));
Coordinates r = mapper.readValue("{\"red\":25}",Coordinates.class);
System.out.println("Deserialization: " + r.getR());
Result:
Serialization: {"r":5}
Deserialization: 25
You can use @jsonAlias
which got introduced in jackson 2.9.0
Example:
public class Info {
@JsonAlias({ "red" })
public String r;
}
This uses r
during serialization, but allows red
as an alias during deserialization. This still allows r
to be deserialized as well, though.
You can use a combination of @JsonSetter, and @JsonGetter to control the deserialization, and serialization of your property, respectively. This will also allow you to keep standardized getter and setter method names that correspond to your actual field name.
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonGetter;
class Coordinates {
private int red;
//# Used during serialization
@JsonGetter("r")
public int getRed() {
return red;
}
//# Used during deserialization
@JsonSetter("red")
public void setRed(int red) {
this.red = red;
}
}
I would bind two different getters/setters pair to one variable:
class Coordinates{
int red;
@JsonProperty("red")
public byte getRed() {
return red;
}
public void setRed(byte red) {
this.red = red;
}
@JsonProperty("r")
public byte getR() {
return red;
}
public void setR(byte red) {
this.red = red;
}
}
It's possible to have normal getter/setter pair. You just need to specify access mode in @JsonProperty
Here is unit test for that:
public class JsonPropertyTest {
private static class TestJackson {
private String color;
@JsonProperty(value = "device_color", access = JsonProperty.Access.READ_ONLY)
public String getColor() {
return color;
};
@JsonProperty(value = "color", access = JsonProperty.Access.WRITE_ONLY)
public void setColor(String color) {
this.color = color;
}
}
@Test
public void shouldParseWithAccessModeSpecified() throws Exception {
String colorJson = "{\"color\":\"red\"}";
ObjectMapper mapper = new ObjectMapper();
TestJackson colotObject = mapper.readValue(colorJson, TestJackson.class);
String ser = mapper.writeValueAsString(colotObject);
System.out.println("Serialized colotObject: " + ser);
}
}
I got the output as follows:
Serialized colotObject: {"device_color":"red"}