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"
You can use this variant:
import lombok.Getter;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
//...
@JsonProperty(value = "rr") // for deserialization
@Getter(onMethod_ = {@JsonGetter(value = "r")}) // for serialization
private String rrrr;
with Lombok getter
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;
}
}
They must have included this as a feature, because now setting a different @JsonProperty
for a getter and setter results in exactly what you would expect (different property name during serialization and deserialization for the same field). Jackson version 2.6.7
Annotating with @JsonAlias
which got introduced with Jackson 2.9+, without mentioning @JsonProperty
on the item to be deserialized with more than one alias(different names for a json property) works fine.
I used com.fasterxml.jackson.annotation.JsonAlias
for package consistency with com.fasterxml.jackson.databind.ObjectMapper
for my use-case.
For e.g.:
@Data
@Builder
public class Chair {
@JsonAlias({"woodenChair", "steelChair"})
private String entityType;
}
@Test
public void test1() {
String str1 = "{\"woodenChair\":\"chair made of wood\"}";
System.out.println( mapper.readValue(str1, Chair.class));
String str2 = "{\"steelChair\":\"chair made of steel\"}";
System.out.println( mapper.readValue(str2, Chair.class));
}
just works fine.
This was not what I was expecting as a solution (though it is a legitimate use case). My requirement was to allow an existing buggy client (a mobile app which already released) to use alternate names.
The solution lies in providing a separate setter method like this:
@JsonSetter( "r" )
public void alternateSetRed( byte red ) {
this.red = red;
}
You can write a serialize class to do that:
public class Symbol
{
private String symbol;
private String name;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class SymbolJsonSerializer extends JsonSerializer<Symbol> {
@Override
public void serialize(Symbol symbol, JsonGenerator jgen, SerializerProvider serializers) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("symbol", symbol.getSymbol());
//Changed name to full_name as the field name of Json string
jgen.writeStringField("full_name", symbol.getName());
jgen.writeEndObject();
}
}
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Symbol.class, new SymbolJsonSerializer());
mapper.registerModule(module);
//only convert non-null field, option...
mapper.setSerializationInclusion(Include.NON_NULL);
String jsonString = mapper.writeValueAsString(symbolList);
I know its an old question but for me I got it working when I figured out that its conflicting with Gson library so if you are using Gson then use @SerializedName("name")
instead of @JsonProperty("name")
hope this helps
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.
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"}
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;
}
}
Source: Stackoverflow.com