Различные названия свойств JSON при сериализации и десериализации
Возможно ли: иметь одно поле в классе, но разные имена для него во время сериализации/десериализации в библиотеке Джексона?
Например, у меня есть класс "Координаты".
class Coordinates{
int red;
}
Для десериализации из JSON нужно иметь такой формат:
{
"red":12
}
Но когда я буду сериализовать объект, результат должен выглядеть следующим образом:
{
"r":12
}
Я попытался реализовать это, применив аннотацию @JsonProperty
как к getter, так и к setter (с разными значениями):
class Coordiantes{
int red;
@JsonProperty("r")
public byte getRed() {
return red;
}
@JsonProperty("red")
public void setRed(byte red) {
this.red = red;
}
}
но я получил исключение:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: непризнанное поле "красный"
Ответы
Ответ 1
Просто протестировано, и это работает:
public class Coordinates {
byte red;
@JsonProperty("r")
public byte getR() {
return red;
}
@JsonProperty("red")
public void setRed(byte red) {
this.red = red;
}
}
Идея заключается в том, что имена методов должны быть разными, поэтому Джексон анализирует его как разные поля, а не как одно поле.
Вот тестовый код:
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());
Результат:
Serialization: {"r":5}
Deserialization: 25
Ответ 2
Вы можете использовать @jsonAlias, который был введен в jackson 2.9.0
Пример:
public class Info {
@JsonAlias({ "r", "red" })
public String r;
}
Ответ 3
Я бы связал две разные пары геттеров/сеттеров с одной переменной:
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;
}
}
Ответ 4
Вы можете использовать комбинацию @JsonSetter и @JsonGetter для управления десериализацией и сериализацией вашего свойства соответственно. Это также позволит вам сохранить стандартизированные имена методов получения и установки, которые соответствуют вашему фактическому имени поля.
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;
}
}
Ответ 5
Это не то, что я ожидал в качестве решения (хотя это законный вариант использования). Мое требование состояло в том, чтобы разрешить существующему багги-клиенту (уже выпущенному мобильному приложению) использовать альтернативные имена.
Решение заключается в предоставлении отдельного метода сеттера следующим образом:
@JsonSetter( "r" )
public void alternateSetRed( byte red ) {
this.red = red;
}
Ответ 6
Возможно иметь нормальную пару геттер/сеттер. Вам просто нужно указать режим доступа в @JsonProperty
Вот unit test для этого:
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);
}
}
Я получил результат следующим образом:
Serialized colotObject: {"device_color":"red"}
Ответ 7
Они должны были включить это как функцию, потому что теперь установка другого @JsonProperty
для геттера и сеттера приводит к тому, что вы ожидаете (другое имя свойства во время сериализации и десериализации для того же поля). Джексон версии 2.6.7
Ответ 8
Вы можете написать сериализованный класс для этого:
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);
Ответ 9
Я знаю, что это старый вопрос, но для меня он заработал, когда я выяснил, что он конфликтует с библиотекой Gson, поэтому, если вы используете Gson, используйте @SerializedName("name")
вместо @JsonProperty("name")
надеюсь, это поможет