Jackson将数组元素反序列化为特定字段 [英] Jackson deserialize array elements into specific fields

查看:678
本文介绍了Jackson将数组元素反序列化为特定字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否存在一个Jackson批注,该批注将允许将数组反序列化为我的POJO的特定字段?我可以使用自定义解串器轻松地做到这一点,但是我希望能与班级一起完成此工作.

例如,我有以下来自Elasticsearch的JSON.

  {
    "_index": "twitter",
    "_type": "tweet",
    "_id": "AVodOsgk0etILSbJamY-",
    "_score": null,
    "_source": {
      "tweetText": "I'm at Residencial Nova Alegria https:\/\/t.co\/4TyK8PAWzB",
      "placeCountry": "Brasil",
      "screenName": "wildelson",
      "cleanedText": "I'm at Residencial Nova Alegria https:\/\/t.co\/4TyK8PAWzB",
      "resolvedUrls": [
        "https:\/\/www.swarmapp.com\/c\/gfULJdQ6umw"
      ],
      "tweetId": "829272906291085314",
      "tweetDate": 1486549042000
    },
    "sort": [
      1486549042000,
      "tweet#AVodOsgk0etILSbJamY-"
    ]
  }

我的POJO如下:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder(value = {
    "enrichedStatus",
    "sortValue",
    "uid"
})
public class TweetHit {
    private final EnrichedStatus enrichedStatus;
    private final Long sortValue;
    private final String uid;

    public TweetHit(EnrichedStatus enrichedStatus, Long sortValue, String uid) {
        this.enrichedStatus = enrichedStatus;
        this.sortValue = sortValue;
        this.uid = uid;
    }

我希望对"sort"数组进行反序列化,该数组在array [0]中将始终为long,在array [1]中将始终为String:

Long sortValue = sort[0]
String uid = sort[1]

我发现了另一个问题,唯一的答案是自定义解串器,如果可以的话,我想避免. Jackson:在对象的不同属性中反序列化JSON-Array

我认为也许可以将@JsonProperty("sort")@JsonFormat(shape = ARRAY)结合使用,但是我仍然看不到指定要反序列化到每个字段中的特定单元格.

注意,这是一个不可变的对象,因此我可能需要该解决方案才能与构造函数内联工作,尽管也许我可以删除final,添加一个空的构造函数,将注释放在字段级别,然后使用Lombok禁用杰克逊是否可以直接进入田野赛场?

解决方案

您可以使用@JsonCreator@JsonProperty批注以及自定义构造函数来实现此目的.由于我不知道class EnrichedStatus是什么样子,因此仅用sort数组简化了您的示例:

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

@Data
class TweetHit {
    private final Long sortValue;
    private final String uid;

    @JsonCreator
    public TweetHit(@JsonProperty("sort") String[] sort) {
        this.sortValue = Long.parseLong(sort[0]);
        this.uid = sort[1];
    }
}

public class StackOverflow {
    public static void main(String[] args) throws IOException {
        String json = "{ \"sort\": [\n" +
                "      1486549042000,\n" +
                "      \"tweet#AVodOsgk0etILSbJamY-\"\n" +
                "    ]\n" +
                "  }";

        ObjectMapper objectMapper = new ObjectMapper();
        TweetHit tweetHit = objectMapper.readValue(json, TweetHit.class);
    }
}

这保留了TweetHit类的不变性,并避免了自定义反序列化器.

我看不到使用具有不同用途的@JsonFormat(shape = ARRAY)来实现此目的的方法.即使有可能,我怀疑它会比接受数组并将其内容分配给字段的构造函数更简单.

如果您也想避免使用@JsonCreator@JsonProperty注释,还请检查此答案.

Is there a Jackson annotation that will allow an array to be deserialized into specific fields of my POJO? I can easily do this with a custom deserializer, but I was hoping to get this done in-line with the class.

For example, I have the following JSON coming back from Elasticsearch.

  {
    "_index": "twitter",
    "_type": "tweet",
    "_id": "AVodOsgk0etILSbJamY-",
    "_score": null,
    "_source": {
      "tweetText": "I'm at Residencial Nova Alegria https:\/\/t.co\/4TyK8PAWzB",
      "placeCountry": "Brasil",
      "screenName": "wildelson",
      "cleanedText": "I'm at Residencial Nova Alegria https:\/\/t.co\/4TyK8PAWzB",
      "resolvedUrls": [
        "https:\/\/www.swarmapp.com\/c\/gfULJdQ6umw"
      ],
      "tweetId": "829272906291085314",
      "tweetDate": 1486549042000
    },
    "sort": [
      1486549042000,
      "tweet#AVodOsgk0etILSbJamY-"
    ]
  }

My POJO as follows:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder(value = {
    "enrichedStatus",
    "sortValue",
    "uid"
})
public class TweetHit {
    private final EnrichedStatus enrichedStatus;
    private final Long sortValue;
    private final String uid;

    public TweetHit(EnrichedStatus enrichedStatus, Long sortValue, String uid) {
        this.enrichedStatus = enrichedStatus;
        this.sortValue = sortValue;
        this.uid = uid;
    }

I want the "sort" array, which will always have a long in array[0] and a String in array[1], to be deserialized as follows:

Long sortValue = sort[0]
String uid = sort[1]

I've found one other question, where the only answer was a custom deserializer, which I would like to avoid if I can. Jackson: Deserialize JSON-Array in different attributes of an object

I thought perhaps I can use @JsonProperty("sort") with @JsonFormat(shape = ARRAY) somehow, but I don't see anyway to specify the specific cell to deserialize into each field.

Note, this is an immutable object and so I likely need the solution to work in-line with the constructor, though maybe I can remove final, add an empty constructor, put the annotations at the field level and use Lombok to disable the setters if Jackson can set directly into the fields?

解决方案

You can approach this with the @JsonCreator and @JsonProperty annotations and a custom constructor. Since I don't know what class EnrichedStatus looks like I simplified your example with just the sort array:

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

@Data
class TweetHit {
    private final Long sortValue;
    private final String uid;

    @JsonCreator
    public TweetHit(@JsonProperty("sort") String[] sort) {
        this.sortValue = Long.parseLong(sort[0]);
        this.uid = sort[1];
    }
}

public class StackOverflow {
    public static void main(String[] args) throws IOException {
        String json = "{ \"sort\": [\n" +
                "      1486549042000,\n" +
                "      \"tweet#AVodOsgk0etILSbJamY-\"\n" +
                "    ]\n" +
                "  }";

        ObjectMapper objectMapper = new ObjectMapper();
        TweetHit tweetHit = objectMapper.readValue(json, TweetHit.class);
    }
}

This preserves immutability of TweetHit class and avoids a custom deserializer.

I can't see a way to do this with a @JsonFormat(shape = ARRAY) that serves a different purpose. Even if it was possible I doubt it would be simpler than a constructor that takes the array and assigns it's content to fields.

Also check this answer if you'd also like to avoid @JsonCreator, @JsonProperty annotations.

这篇关于Jackson将数组元素反序列化为特定字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆