使用Jackson来实现不带注释的toString()

时间:2018-06-21 22:07:47

标签: java jackson

我想使用Jackson来实现toString()以返回对象的JSON表示,但是我不想在我的代码中使用任何Jackson注释。

我尝试了以下实现方式:

public String toString()
{
    Map<String,Object> ordered = ImmutableMap.<String, Object>builder().
        put("createdAt", createdAt.toString()).
        put("address", address.toString()).
        build();

    ObjectMapper om = new ObjectMapper();
    om.enable(SerializationFeature.INDENT_OUTPUT);
    try
    {
        return om.writeValueAsString(object);
    }
    catch (JsonProcessingException e)
    {
        // Unexpected
        throw new AssertionError(e);
    }
}

这对于简单的字段来说效果很好,但是如果“地址”具有其自己的字段,那么您将无法获取此地址:

{
  "address" : {
    "value" : "AZ4RPBb1kSkH4RNewi4NXNkBu7BX9DmecJ",
    "tag" : null
}

我得到以下输出:

{
  "address" : "{\n\"value\" : \"AZ4RPBb1kSkH4RNewi4NXNkBu7BX9DmecJ\",\n        \"tag\" : null"
}

换句话说,与JsonNode相对,地址值被视为字符串。

要澄清:

  • 一方面,我想控制将简单的类字段转换为String的方式。我不想使用Jackson的内置转换器。
  • 另一方面,对于复杂的字段,将String值返回给Jackson会导致错误的行为。

我相信我可以通过向所有类添加公共toJson()方法来解决此问题。该方法将返回Map<String, JsonNode>,其中,对于简单字段,该值是一个字符串节点;对于复杂字段,该值是toJson()的输出。不幸的是,这将污染我的公共API的实现细节。

如何在不污染类的公共API的情况下实现所需的行为?

更新:我刚刚在https://stackoverflow.com/a/9599585/14731看到了一个有趣的答案……也许我可以将复杂字段的String值转换回JsonNode,然后再将它们传递给Jackson

1 个答案:

答案 0 :(得分:0)

我认为您应该在每个类中实现两种方法-一种用于转储数据,第二种用于从原始数据结构构建JSON。您需要将其分开,否则每次封装嵌套的toString()调用时,嵌套的层次都会越来越深。

一个例子:

class Address {
    private BigDecimal yourField;

    /* …cut… */

    public Map<String, Object> toMap() {
        Map<String, Object> raw = new HashMap<>();
        raw.put("yourField", this.yourField.toPlainString());
        /* more fields */
        return raw;
    }

    @Override
    public String toString() {
        // add JSON processing exception handling, dropped for readability
        return new ObjectMapper().writeValueAsString(this.toMap());
    }
}

class Employee {
    private Address address;

    /* …cut… */

    public Map<String, Object> toMap() {
        Map<String, Object> raw = new HashMap<>();
        raw.put("address", this.address.toMap());
        /* more fields */
        return raw;
    }

    @Override
    public String toString() {
        // add JSON processing exception handling, dropped for readability
        return new ObjectMapper().writeValueAsString(this.toMap());
    }
}