【问题标题】:How to parse "{}" empty value (into String)如何解析“{}”空值(转换为字符串)
【发布时间】:2023-04-09 17:39:02
【问题描述】:

给定 json:

{
  "name" : {}
}

我想使用 com.fasterxml.jackson 将其解析为以下 Java 对象:

class MyClass {
  private String name;
}

如果你尝试一下,你会得到:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

有什么方法可以配置 jackson 反序列化器(最好在全局范围内)它可以将这些 empty objects 处理为 nulls 而无需更改属性类型(来自字符串)?

【问题讨论】:

  • 你的 json 不应该是 { "name" : null } ?我们不在 json 中用 {} 表示空对象。 stackoverflow.com/questions/21120999/representing-null-in-json
  • Here 他们提到它不支持解析空对象。该线程的一个想法是在解析之前仅在 JSON 字符串上使用 replace("{}", "null"),这漂亮,但可能会起作用。
  • 应该是,但是那个 JSON 不是我的。而且据我了解,{} 依然有效,对吧?
  • 嗯,您应该始终能够使用自定义反序列化器将空对象转换为字符串。但是,对空值和非空值使用不同的类型是灾难性的,最好按照其他人的建议使用"name":null - 或者可能是"name":""。必须检查类型最终肯定会咬你一口。
  • 对的人,我知道name: {} for String 不好。但正如我所说,我不会产生这种凌乱的 JSON :-)。

标签: java json jackson fasterxml


【解决方案1】:

为此,您可以编写自己的反序列化器。在 this 之后,您扩展了 StdDeserializer 并将其注册到类中。


作者编辑:

我已经为字符串使用了以下反序列化器,它工作正常,谢谢:

public class EmptyObjectDeserializer extends StdDeserializer<String> {

    public EmptyObjectDeserializer() {
        this(null);
    }

    public EmptyObjectDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        return node.asText("");
    }
}

【讨论】:

  • 这根本没有帮助。这没有描述问题是什么以及正确的解决方案。
  • 将为String.class 尝试。感谢您的建议。
  • 这可能作为评论传递,而不是作为答案传递。
  • 我已编辑答案以包含我的自定义字符串反序列化器。该解决方案运行良好,并且是我发现的选项中最好的。编辑正在等待审核。
  • 有点矫枉过正,可能更简单,不需要反序列化器,只需为Name添加一个类
【解决方案2】:

在 json 中,{} 是一个Object,这意味着它可以有字段(就像 Java 中的 POJO)。当您尝试将其反序列化为String 时,它会引发异常(想象一下尝试将 POJO 分配给 Java 中的字符串引用)。

在这种情况下,有两种选择:

  • 将您的课程配置为不包含空字段。这可以通过 ObjectMapper 实例上的注释或配置来完成,例如:

    @JsonInclude(Include.NON_NULL)
    class MyClass {
      private String name;
    }
    

    mapper.setSerializationInclusion(Include.NON_EMPTY);

    如果响应中没有空 name,则此选项可能不起作用。如果它是一个非 null 值的对象,Jackson 将尝试将其反序列化为 String 并失败。

  • name 的类型更改为Object(或者更确切地说,一个包含响应可以包含的所有元素的 POJO)。然而,这意味着您需要更改访问 name 元素的代码,因为它将不再是 String

【讨论】:

  • @JsonInclude 的第一个建议仅用于序列化 - 这不是我要问的。第二个建议是我想到但不想做的事情。谢谢
  • 如果您的请求包含name 对象下的字段,那么如果您想反序列化响应内容,您别无选择,只能更改name 字段的类型。
【解决方案3】:

无需编写自己的反序列化器,只需将名称对象封装在一个类中即可:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
        "name"
})
public class JsonExample {
        @JsonProperty("name")
        public Name name;
}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
        "first",
        "last"
})
public class Name {
    @JsonProperty("first")
    public String first_name;
    @JsonProperty("last")
    public String last_name;
}

这里以名字和姓氏为例...不知道您的 Name 对象中的内容 所以你可以使用你的映射器:

JsonExample obj = mapper.readValue(file, JsonExample.class);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    相关资源
    最近更新 更多