如何使用 ObjectMapper 在没有默认构造函数的情况下反序列化不可变对象?

新手上路,请多包涵

我想使用 com.fasterxml.jackson.databind.ObjectMapper 序列化和反序列化一个不可变对象。

不可变类看起来像这样(只有 3 个内部属性、getter 和构造函数):

 public final class ImportResultItemImpl implements ImportResultItem {

    private final ImportResultItemType resultType;

    private final String message;

    private final String name;

    public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
        super();
        this.resultType = resultType;
        this.message = message;
        this.name = name;
    }

    public ImportResultItemImpl(String name, ImportResultItemType resultType) {
        super();
        this.resultType = resultType;
        this.name = name;
        this.message = null;
    }

    @Override
    public ImportResultItemType getResultType() {
        return this.resultType;
    }

    @Override
    public String getMessage() {
        return this.message;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

但是,当我运行此单元测试时:

 @Test
public void testObjectMapper() throws Exception {
    ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
    String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
    System.out.println("serialized: " + serialized);

    //this line will throw exception
    ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}

我得到这个例外:

 com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
    at
... nothing interesting here

这个异常要求我创建一个默认构造函数,但这是一个不可变对象,所以我不想拥有它。它将如何设置内部属性?它会完全混淆 API 的用户。

所以我的问题是: 我可以在没有默认构造函数的情况下以某种方式取消/序列化不可变对象吗?

原文由 Michal Krasny 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 845
2 个回答

要让 Jackson 知道如何创建反序列化对象,请为构造函数使用 @JsonCreator@JsonProperty 注释,如下所示:

 @JsonCreator
public ImportResultItemImpl(@JsonProperty("name") String name,
        @JsonProperty("resultType") ImportResultItemType resultType,
        @JsonProperty("message") String message) {
    super();
    this.resultType = resultType;
    this.message = message;
    this.name = name;
}

原文由 Sergei 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用私有默认构造函数,Jackson 将通过反射填充字段,即使它们是私有最终的。

编辑:如果您有继承,则为父类使用受保护/包保护的默认构造函数。

原文由 tkruse 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题