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 将使用以下值调用此方法:ABCCBACBBCA.

我找到了解决方案。我不得不标记 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 调用。