如何将单个 json 属性 反序列化为多个 Java 字段(如果可能的话使用转换器)
How to deserialize single json property into multiple Java fields (if possible with converter)
有这个class:
@Getter
@Setter
public class Result {
private String positionText;
private Integer positionNumber;
.. many many other properties ..
}
并反序列化这个 json:
[
{
"position": "1",
.. many many other properties ..
},
{
"position": "FOO",
.. many many other properties ..
},
..
}
如何将 position
json 属性 反序列化为 positionText
和 positionNumber
Java 字段?
public abstract class ResultMixIn {
@JsonProperty("position")
abstract String getPositionText();
@JsonProperty("position")
abstract Integer getPositionNumber();
}
但这给出了一个:
Conflicting getter definitions for property "position": com.example.domain.Result#getPositionText() vs com.example.domain.Result#getPositionNumber()
同样将抽象 getter 更改为 setter 也没有什么不同。
如果可能的话,我想避免完全成熟的 ResultDeserializer
扩展 StdDeserializer
,因为 Result
class 有更多我不想反序列化的属性”手工”。
PS:我不关心序列化。我只是反序列化模型。
首先需要注释Result
class的属性,
这样 Jackson 将反序列化 positionText
属性,
但不是 positionNumber
。
您将在 taylor-made 反序列化器中自己完成后者。
@Getter
@Setter
public class Result {
@JsonProperty("position")
private String positionText;
@JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
默认情况下,Jackson 会使用 BeanDeserializer
来反序列化 Result
对象。
但是你想要这个反序列化器的实现稍微修改一下。
此答案的其余部分主要改编自已接受的答案
问题 How do I call the default deserializer from a custom deserializer in Jackson.
像往常一样,您的反序列化器从 StdDeserializer<Result>
扩展而来,
但它也实现了 ResolvableDeserializer
接口。
在 deserialize
方法中,大部分工作都委托给了默认的反序列化器
(在本例中是 BeanDeserializer
),我们从 Jackson 那里得到。
我们只添加了一个小的额外逻辑来设置 positionNumber
属性
基于 positionText
属性.
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
@Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
最后你需要告诉杰克逊你想要上面的东西ResultDeserializer
用于反序列化 Result
个对象。
这是通过 ObjectMapper
的以下自定义完成的,
这会将你的 ResultDeserializer
包裹在 Jackson 的周围
默认反序列化器,仅当要反序列化 Result
对象时:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
然后您可以照常反序列化您的 JSON 内容,例如:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});
有这个class:
@Getter
@Setter
public class Result {
private String positionText;
private Integer positionNumber;
.. many many other properties ..
}
并反序列化这个 json:
[
{
"position": "1",
.. many many other properties ..
},
{
"position": "FOO",
.. many many other properties ..
},
..
}
如何将 position
json 属性 反序列化为 positionText
和 positionNumber
Java 字段?
public abstract class ResultMixIn {
@JsonProperty("position")
abstract String getPositionText();
@JsonProperty("position")
abstract Integer getPositionNumber();
}
但这给出了一个:
Conflicting getter definitions for property "position": com.example.domain.Result#getPositionText() vs com.example.domain.Result#getPositionNumber()
同样将抽象 getter 更改为 setter 也没有什么不同。
如果可能的话,我想避免完全成熟的 ResultDeserializer
扩展 StdDeserializer
,因为 Result
class 有更多我不想反序列化的属性”手工”。
PS:我不关心序列化。我只是反序列化模型。
首先需要注释Result
class的属性,
这样 Jackson 将反序列化 positionText
属性,
但不是 positionNumber
。
您将在 taylor-made 反序列化器中自己完成后者。
@Getter
@Setter
public class Result {
@JsonProperty("position")
private String positionText;
@JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
默认情况下,Jackson 会使用 BeanDeserializer
来反序列化 Result
对象。
但是你想要这个反序列化器的实现稍微修改一下。
此答案的其余部分主要改编自已接受的答案 问题 How do I call the default deserializer from a custom deserializer in Jackson.
像往常一样,您的反序列化器从 StdDeserializer<Result>
扩展而来,
但它也实现了 ResolvableDeserializer
接口。
在 deserialize
方法中,大部分工作都委托给了默认的反序列化器
(在本例中是 BeanDeserializer
),我们从 Jackson 那里得到。
我们只添加了一个小的额外逻辑来设置 positionNumber
属性
基于 positionText
属性.
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
@Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
最后你需要告诉杰克逊你想要上面的东西ResultDeserializer
用于反序列化 Result
个对象。
这是通过 ObjectMapper
的以下自定义完成的,
这会将你的 ResultDeserializer
包裹在 Jackson 的周围
默认反序列化器,仅当要反序列化 Result
对象时:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
然后您可以照常反序列化您的 JSON 内容,例如:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});