为什么在没有默认构造函数的情况下将JSON编码的字符串转换为Java类实例会失败?

时间:2018-04-04 09:22:44

标签: java json jackson vert.x

我有以下代码,它将T类型的实例编码为String。 然后尝试将编码的字符串转换回类T的实例。

package com.ncr.nep.messaging.notifications.tests;

import java.io.IOException;
import java.io.Serializable;    
import com.fasterxml.jackson.databind.ObjectMapper;    
import io.vertx.core.json.JsonObject;

class T implements Serializable {
    private String channel;

    //public T() { }
    public T(String channel) {
        super();
        this.channel = channel;
    }
    public String getChannel() {
        return channel;
    }
}
public class Test {
    public static void main(String[] args) {
        T t = new T("abc");
        String enc = JsonObject.mapFrom(t).encode();
        System.out.println(enc); //prints: {"channel":"abc"}
        //now back from String to T
        try {
            t = new ObjectMapper().readValue(enc,T.class);
            System.out.println(t.getChannel());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

readValue方法调用抛出以下异常:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.ncr.nep.messaging.notifications.tests.T: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {"channel":"abc"}; line: 1, column: 2]

取消注释默认构造函数可修复问题并生成正确的T实例。

我发现很难想象这个实用工具类的设计者ObjectMapper会对他们的客户施加如此大的限制。
请注意,我可以声明通道是最终的,在这种情况下,为了解决问题,不仅需要添加默认构造函数,而且还需要更改所有成员 - 不是最终的#39;。 ..

所以我的问题是这样的:
如果类T的设计者明确禁止默认构造函数,该怎么办?还有什么可以做的吗?是否有注释可以做到这一点?

3 个答案:

答案 0 :(得分:3)

您可以尝试使用@JsonCreator注释构造函数,使用@JsonProperty注释参数

@JsonCreator
public T(@JsonProperty("channel") String channel) {
    super();
    this.channel = channel;
}

答案 1 :(得分:1)

问题是天气MOXy或Jackson都需要一种方法来创建一个对象。您只提供T.class。他们应该如何知道如何使用你的构造函数。在你的情况下,它可能很简单,但对于

public T(String a, String b) {..}

这将更加困难。在这种情况下,您可以添加另一个约束,如参数名称需要匹配json属性名称。我想这与默认的构造函数有同样的缺点。

更新: 我不知道@ Link64所描述的解决方案,但是如果这更好的话。我不知道。 MOXy提供XMLAdapter来创建对象。例如,如果T类不在您的控制之下。

答案 2 :(得分:0)

JavaBeans模式要求:

  

它们是可序列化的,具有零参数构造函数,并允许使用getter和setter方法访问属性。

由于这种形式的java类经常在许多框架中使用,因此用户应该期望这种形式。

解决方案"如果T的设计者禁止默认构造函数"取决于具体的用例。大多数情况下我会说这样的类不是bean,因此不是一个好的转移对象 - 你最好使用你自己的转移对象,它遵循预期的格式,并提供从/转换它的方法目标类。