【问题标题】:How to pass constructor's parameters with jackson?如何用杰克逊传递构造函数的参数?
【发布时间】:2015-01-23 20:05:29
【问题描述】:

我正在尝试使用 Jackson 对对象进行去耳化

this.prepareCustomMapper().readValue(response.getBody(), EmailResponse.class);

我有这个例外:

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class com.despegar.social.automation.services.emailservice.response.EmailResponse]: can not instantiate from JSON object (need to add/enable type information?)
 at [Source: java.io.StringReader@4f38f663; line: 1, column: 12] (through reference chain: com.despegar.social.automation.services.emailservice.response.EmailsResponse["items"])
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.java:746)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:683)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580)
    at org.codehaus.jackson.map.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:217)

我知道这是因为这是我的构造函数:

public class EmailResponse extends MyServiceResponse {

    private String id;
    private String user_id;
    private String email;
    private Boolean is_primary;
    private Boolean is_confirmed;

    public EmailResponse(HttpResponse request) {
        super(request);
    }
}

所以,我的构造函数接收到 HttpResponse 参数并且我没有传递它,但我不知道该怎么做。我不能用空的构造函数多收费,因为我需要它以这种方式接收 HttpResponse 对象。 当我调用 readValue() 方法时,有什么方法可以传递这个构造函数参数吗?或者在这种情况下最好的选择是什么?我感谢您的帮助。问候

【问题讨论】:

  • 我不能用空的构造函数多收费,因为我需要它以这种方式接收 HttpResponse 对象:你为什么不能保留你已经拥有的构造函数,并添加另一个构造函数没有争论?这就是平均加载。
  • 因为它必须通过构造函数接收 HttpResponse 对象。如果我创建一个空的构造函数,我将不得不创建 setter 方法来输入 HttpResponse 而我不想这样做。是不是可以告诉杰克逊在解散期间在构造函数中使用什么参数?
  • 这里有一些 JSON:{"foo":"bar"}。你要求 JSON 解组它。为什么要使用 HttpResponse?它会在哪里找到它?这就是你要找的东西:fasterxml.github.io/jackson-databind/javadoc/2.3.0/com/…
  • 我只想将 HttpResponse 对象存储到 EmailResponse 中(我在代码的另一部分需要 HttpResponse 数据),但我不想在 EmailResponse 类中创建公共设置方法,并受保护或“无修饰符”也不是选项,所以我认为可行的唯一方法是通过构造函数传递它。我知道它有点复杂:P 但无论如何谢谢

标签: java json serialization mapping jackson


【解决方案1】:

您可以使用the Jackson value injection feature 将不属于输入 JSON 的对象引用作为构造函数参数传递。这是一个例子:

public class JacksonInjectExample {
    private static final String JSON = "{\"field1\":\"value1\", \"field2\":123}";

    // HttpResponse in your case
    public static class ExternalObject {
        @Override
        public String toString() {
            return "MyExternalObject";
        }
    }

    public static class Bean {
        // make fields public to avoid writing getters in this example
        public String field1;
        public int field2;

        private ExternalObject external;

        public Bean(@JacksonInject final ExternalObject external) {
            this.external = external;
        }

        @Override
        public String toString() {
            return "Bean{" +
                    "field1='" + field1 + '\'' +
                    ", field2=" + field2 +
                    ", external=" + external +
                    '}';
        }
    }

    public static void main(String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();
        final InjectableValues.Std injectableValues = new InjectableValues.Std();
        injectableValues.addValue(ExternalObject.class, new ExternalObject());
        mapper.setInjectableValues(injectableValues);

        final Bean bean = mapper.readValue(JSON, Bean.class);
        System.out.println(bean);
    }
}

输出:

Bean{field1='value1', field2=123, external=MyExternalObject}

【讨论】:

  • 谢谢!我会试试看!问候
  • 这段代码有效吗?我正在使用类似的人,并且映射器注入 null
  • 该代码适用于最新的 Jackson 版本。你是哪个版本的?
  • 很抱歉这是我的错误。我的构造函数有问题,但我已经解决了!谢谢,代码没问题!
  • 我曾尝试将这种方法用于反序列化器,但似乎我遗漏了什么...stackoverflow.com/questions/60061131/…
【解决方案2】:

您可以编写自定义反序列化器:http://jackson.codehaus.org/1.5.7/javadoc/org/codehaus/jackson/map/annotate/JsonDeserialize.html

在这种情况下,您将能够将所需的任何值传递给构造函数。您需要在 EmailResponse 上添加 @JsonDeserialize 注释,例如:

@JsonDeserialize(using = EmailResponseDeserializer.class)

反序列化器实现示例:

public class EmailResponseDeserializer extends JsonDeserializer<EmailResponse> {
    HttpResponse httpResponse;

    public EmailResponceDeserializer(HttpResponse httpResponse) {
        this.httpResponse = httpResponse;
    }

    @Override
    public EmailResponse deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) ((IntNode) node.get("id")).numberValue();
        String email = node.get("email").asText();

        EmailResponse emailResponse = new EmailResponse(httpResponse)
        emailResponse.setId(id);
        emailResponse.setEmail(email);
        // other properties

        return emailResponse;
    }
}

您还需要注册自定义反序列化器:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(EmailResponse.class, new EmailResponseDeserializer(httpRespose));
mapper.registerModule(module);

一般来说,我会说通过将 HttpResponse 添加到 EmailRespose bean 中,您正在向 DTO 对象中添加一些不应该有的实现。我认为将 httpResponse 设置为自定义反序列化器然后将其设置为 EmailResponse 不是一个好主意,但没有什么能阻止您这样做。

希望这会有所帮助。

【讨论】:

猜你喜欢
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 2016-12-31
  • 2018-08-02
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
  • 2017-03-30
相关资源
最近更新 更多