【问题标题】:Automatic deserialization of String to Object with Jackson使用 Jackson 将字符串自动反序列化为对象
【发布时间】:2021-01-01 14:28:23
【问题描述】:

上下文

假设你有:

public class Dto {
  private String name;
  private String List<Custom> customs;

  // getters and setters...
}

public class Custom {
  private String something;
  private String else;
  
  // getters and setters...
}

您的 Spring MVC RestController 收到 Dto 的列表:

@PostMapping
public String create(@RequestBody @Valid List<Dto> dtos) {
  return myService.process(features);
}

输入

但是,您知道将数据发送到您的控制器的客户端服务将发送如下内容:

[
  {
    "name": "Bob",
    "customs": [
      "{\n        \"something\": \"yes\",\n        \"else\": \"no\"\n      }"
    ]
  }
]

请注意List&lt;Custom&gt; 实际上最终会以List&lt;String&gt; 的形式接收。请假设这不能在客户端更改,我们必须在服务器端处理它。

问题

是否有 Jackson 注释会自动获取输入 String 并尝试将其序列化为 Custom 类?

尝试

一些没有用的东西,包括:

@JsonSerialize(using = ToStringSerializer.class)
private List<Custom> customs;

随着

public Custom(String json) {
  try {
    new ObjectMapper().readerFor(Custom.class).readValue(json);
  } catch (JsonProcessingException e) {
    e.printStackTrace();
  }
}

事实上,我们不得不将customs 类型更改为List&lt;String&gt;,并添加一个实用方法,该方法使用ObjectMapperString 转换为Custom。这是相当不满意的。

【问题讨论】:

  • 那是因为在您的尝试中您使用了“JsonSerialize”这个注释用于响应。您需要使用 JsonDeserialize 与此您可以做您的自定义反序列化器,应该工作
  • @Marco 好点。尽管如此,我的问题主要是关于获得自动的东西。当输入 String 与所需的 Custom 类匹配时,我宁愿不必维护自定义反序列化器。
  • 示例负载不是有效的JSON。我想,当你想掩盖真实的人时,你打破了它。我说的对吗?
  • @MichałZiober 抱歉,我忘了转义引号。这是固定的。

标签: java spring spring-boot spring-mvc jackson


【解决方案1】:

您需要实现自定义反序列化器或转换器,用于将给定的有效负载转换为所需的类型。您可以使用的一个技巧是创建新的 ObjectMapper 并将其用于内部反序列化。

示例用法:

class CustomConverter extends StdConverter<String, Custom> {

    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public Custom convert(String value) {
        try {
            return mapper.readValue(value, Custom.class);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException(value);
        }
    }
}

class Dto {
    private String name;

    @JsonDeserialize(contentConverter = CustomConverter.class)
    private List<Custom> customs;

}

【讨论】:

    【解决方案2】:

    您需要创建一个自定义反序列化器。

    public class CustomDeserializer extends StdDeserializer<Custom> { 
     
        public CustomDeserializer() { 
            this(null); 
        } 
     
        public CustomDeserializer(Class<?> vc) { 
            super(vc); 
        }
     
        @Override
        public Custom deserialize(JsonParser jp, DeserializationContext ctxt) 
          throws IOException, JsonProcessingException {
            JsonNode node = jp.getCodec().readTree(jp);
            int id = (Integer) ((IntNode) node.get("id")).numberValue();
            String name = node.get("name").asText();
            ...
            return new Custom(id, name, ...);
        }
    }
    

    并在Custom 类上注册反序列化器:

    @JsonDeserialize(using = CustomDeserializer.class)
    public class Custom {
      ...
    }
    

    【讨论】:

    • 但这不是一个自动过程。是否没有Deserializer 负责将输入String 分析为带有额外空白(属性声明之间的spacesenters)指定特定类的Json?
    • Jackson 需要注解或反序列化器/序列化器。另一方面,Gson 更加灵活。
    猜你喜欢
    • 2019-08-21
    • 1970-01-01
    • 2017-08-02
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多