Spring 中的@RequestBody 从字符串自动反序列化为对象
Automatic deserialization from String to object for @RequestBody in Spring
我在序列化方面遇到问题,尽管我一直在四处寻找,但我无法找到解决方案。
我的 @RestController
里面有类似于此方法的东西和端点:
public ResponseEntity<String>(@RequestBody RequestObject requestObject )
RequestObject
看起来像这样:
public class RequestObject {
private Driver driver;
private List<Tracks> tracks;
//constructors, getters and setters
}
public class Tracks {
private Enum1 name;
private List<Enum2> missions;
//constructors, getters and setters
}
那么,Enum2 的List
就有问题了。这是因为我从 JSON 收到的不是字符串列表,而是一个字符串,我需要对其进行解析以转换为 Enum2
的值
所以 Enum2
看起来像这样:
A,
B,
C;
我从请求中得到的 JSON 是:
{
"driver" : {
"name" : "myname"
}
},
"tracks" : [
{
"name" : "madrid",
"missions" : "ABCCBA"
},
{
"name" : "barcelona",
"mission" : "CBBCA"
},
]
}
除 List<Enum2> missions
之外,所有反序列化都开箱即用(包括所有嵌套枚举)
我设法做了一个肮脏的把戏,但我想以正确的方式来做,我的理解是编写某种反序列化器,它在控制器被触发时运行,并完成所有解析并从字符串转换为列表(这个拆分代码我有,但我不知道放在哪里)。
目前我正在收到这个
2021-09-13 21:02:34.924 WARN 99904 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.ArrayList<org.package.model.Enum2>` from String value (token `JsonToken.VALUE_STRING`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<org.model.Enum2>` from String value (token `JsonToken.VALUE_STRING`)
at [Source: (PushbackInputStream); line: 13, column: 26] (through reference chain: org.model.RequestObject["missions"]->java.util.ArrayList[0]-org.model.Track["missions"])]
有没有办法做到这一点?
可能,不使用任何 Jackson
注释的最简单解决方案是使用自定义 setter
方法:
private void setMissions(String value) {
this.missions = convert_value_to_list_of_enums;
}
Jackson
将使用以下值调用此方法:ABCCBA
和 CBBCA
.
我找到了解决方案。我不得不标记 Track
如下:
@JsonDeserialize(using = TrackDeserializer.class)
public class Track
然后写 TrackDeserializer
:
public class TrackDeserializer extends JsonDeserializer<Track>{
@Override
public Track deserialize(JsonParser j, DeserializationContext ctxt) throws IOException{
JsonNode jsonNode = j.getCodec().readTree(jsonParser);
String name = jsonNode.get("name").asText();
final List<Enum2> enum = parseEnums(jsonNode.get("mission").asText());
return new Track(name, enum);
}
并且parseEnums
进行列表的拆分和转换。
现在 TrackDeserializer
会针对问题中给定 JSON 的每个 Track
调用。
我在序列化方面遇到问题,尽管我一直在四处寻找,但我无法找到解决方案。
我的 @RestController
里面有类似于此方法的东西和端点:
public ResponseEntity<String>(@RequestBody RequestObject requestObject )
RequestObject
看起来像这样:
public class RequestObject {
private Driver driver;
private List<Tracks> tracks;
//constructors, getters and setters
}
public class Tracks {
private Enum1 name;
private List<Enum2> missions;
//constructors, getters and setters
}
那么,Enum2 的List
就有问题了。这是因为我从 JSON 收到的不是字符串列表,而是一个字符串,我需要对其进行解析以转换为 Enum2
所以 Enum2
看起来像这样:
A,
B,
C;
我从请求中得到的 JSON 是:
{
"driver" : {
"name" : "myname"
}
},
"tracks" : [
{
"name" : "madrid",
"missions" : "ABCCBA"
},
{
"name" : "barcelona",
"mission" : "CBBCA"
},
]
}
除 List<Enum2> missions
我设法做了一个肮脏的把戏,但我想以正确的方式来做,我的理解是编写某种反序列化器,它在控制器被触发时运行,并完成所有解析并从字符串转换为列表(这个拆分代码我有,但我不知道放在哪里)。
目前我正在收到这个
2021-09-13 21:02:34.924 WARN 99904 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.ArrayList<org.package.model.Enum2>` from String value (token `JsonToken.VALUE_STRING`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<org.model.Enum2>` from String value (token `JsonToken.VALUE_STRING`)
at [Source: (PushbackInputStream); line: 13, column: 26] (through reference chain: org.model.RequestObject["missions"]->java.util.ArrayList[0]-org.model.Track["missions"])]
有没有办法做到这一点?
可能,不使用任何 Jackson
注释的最简单解决方案是使用自定义 setter
方法:
private void setMissions(String value) {
this.missions = convert_value_to_list_of_enums;
}
Jackson
将使用以下值调用此方法:ABCCBA
和 CBBCA
.
我找到了解决方案。我不得不标记 Track
如下:
@JsonDeserialize(using = TrackDeserializer.class)
public class Track
然后写 TrackDeserializer
:
public class TrackDeserializer extends JsonDeserializer<Track>{
@Override
public Track deserialize(JsonParser j, DeserializationContext ctxt) throws IOException{
JsonNode jsonNode = j.getCodec().readTree(jsonParser);
String name = jsonNode.get("name").asText();
final List<Enum2> enum = parseEnums(jsonNode.get("mission").asText());
return new Track(name, enum);
}
并且parseEnums
进行列表的拆分和转换。
现在 TrackDeserializer
会针对问题中给定 JSON 的每个 Track
调用。