序列化和反序列化过程中 JSON 属性的不同名称
Posted
技术标签:
【中文标题】序列化和反序列化过程中 JSON 属性的不同名称【英文标题】:Different names of JSON property during serialization and deserialization 【发布时间】:2012-01-23 12:36:23 【问题描述】:是否有可能:类中有一个字段,但在 Jackson 库中的序列化/反序列化过程中有不同的名称?
例如,我有“坐标”类。
class Coordinates
int red;
对于 JSON 的反序列化,希望具有如下格式:
"red":12
但是当我序列化对象时,结果应该是这样的:
"r":12
我尝试通过在 getter 和 setter(具有不同的值)上应用 @JsonProperty
注释来实现这一点:
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
【讨论】:
与 jaxb 一样吗? 这对Enum
s 有用吗?【参考方案2】:
您可以使用在 jackson 2.9.0 中引入的@jsonAlias
例子:
public class Info
@JsonAlias( "red" )
public String r;
这在序列化期间使用r
,但在反序列化期间允许red
作为别名。不过,这仍然允许 r
被反序列化。
【讨论】:
documentation for @JsonAlias 明确声明它是has no effect during serialization where primary name is always used
。这不是 OP 想要的。
@XaeroDegreaz 我猜@Asura 的意思是,您可以使用r
作为主要名称,但red
用于@JsonAlias
,它允许将其序列化为r
,但添加@ 987654332@ 在反序列化时被识别。用@JsonProperty("r")
和@JsonAlias("red")
注释它应该可以很好地解决给定的问题。【参考方案3】:
您可以使用@JsonSetter 和@JsonGetter 的组合来分别控制您的属性的反序列化和序列化。这也将允许您保留与您的实际字段名称相对应的标准化 getter 和 setter 方法名称。
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;
【讨论】:
【参考方案4】:我会将两个不同的 getter/setter 对绑定到一个变量:
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;
【讨论】:
但是在这种情况下,在序列化过程中,我们将获得两个属性:“r”和“red”,具有相同的值。 @JsonIgnore 关于您不想处理的方法将解决该问题 现在有更方便的注解:@JsonGetter
和@JsonSetter
。因此可以准确设置序列化程序的行为方式。【参考方案5】:
可以有正常的 getter/setter 对。您只需要在@JsonProperty
中指定访问模式
这里是单元测试:
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"
【讨论】:
以上解决方案对我有用。我正在使用 Spring Rest 4 和 jackson 2.9.10【参考方案6】:你可以使用这个变体:
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;
使用 Lombok 吸气剂
【讨论】:
【参考方案7】:这不是我所期望的解决方案(尽管它是一个合法的用例)。我的要求是允许现有的错误客户端(已经发布的移动应用程序)使用备用名称。
解决方案在于提供一个单独的 setter 方法,如下所示:
@JsonSetter( "r" )
public void alternateSetRed( byte red )
this.red = red;
【讨论】:
【参考方案8】:使用 Jackson 2.9+ 引入的 @JsonAlias
进行注释,而无需在要反序列化的项目上使用多个别名(json 属性的不同名称)提及 @JsonProperty
工作正常。
我使用com.fasterxml.jackson.annotation.JsonAlias
与com.fasterxml.jackson.databind.ObjectMapper
用于我的用例的包一致性。
例如:
@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));
工作正常。
【讨论】:
【参考方案9】:我知道这是一个老问题,但对我来说,当我发现它与 Gson 库冲突时,我就开始工作了,所以如果您使用 Gson,请使用 @SerializedName("name")
而不是 @JsonProperty("name")
希望这会有所帮助
【讨论】:
【参考方案10】:他们必须将此作为一项功能包含在内,因为现在为 getter 和 setter 设置不同的 @JsonProperty
会产生您所期望的结果(同一字段的序列化和反序列化期间的不同属性名称)。杰克逊版本 2.6.7
【讨论】:
【参考方案11】:就我而言,我必须阅读巴西葡萄牙语的输入并生成英语输出。
因此,对我有用的解决方法是使用@JsonAlias
而不是@JsonProperty
:
// pseudo-java
@Value
public class User
String username;
public User(
@JsonAlias("nome_usuario") String username)
// ...
【讨论】:
【参考方案12】:您可以编写一个序列化类来做到这一点:
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);
【讨论】:
以上是关于序列化和反序列化过程中 JSON 属性的不同名称的主要内容,如果未能解决你的问题,请参考以下文章