簡體   English   中英

如何打開傑克遜列表中包含列表的項目?

[英]How do I unwrap a list of list wrapped items in Jackson?

我有一個類似於這個的bean:

public class Product {

    public String id;
    public String vendor;
    public Set<Image> images;
}

public class Image {

    public String originalSrc;
}

我正在嘗試反序列化類似於此的JSON:

{
  "id": "gid:\/\/mysite\/Product\/1853361520730",
  "vendor": "gadgetdown",
  "images": {
    "edges": [
      {
        "node": {
          "originalSrc": "https:\/\/cdn.something.com"
        }
      },
      {
        "node": {
          "originalSrc": "https:\/\/cdn.something.com"
        }
      }
    ]
  }

我無法反序列化對象,因為每個image對象都包含在node對象中並且共同包含在edges對象中。


編輯:為了清楚起見,我不想通過使用bean來實現這一點,這個例子是一個簡化,JSON有效負載中的所有數組項都包含在這個edgesnode表示中。

因此, images不是一個set它是一個帶有edges列表的JSONObject

public class Images {

   private List<Edge> edges;

    }

每個Edge包含Node對象,

public class Edge {

   private Node node;

   }

每個Node都有單個String屬性originalSrc

public class Node  {

 private String originalSrc;

  }

如果每個列表都具有如下結構:

{
  "images": {
    "edges": [
      {
        "node": {
          "entry": "entry-value"
        }
      }
    ]
  }
}

每個列表都是帶有edges屬性的JSON Object ,數組中的每個元素都由具有node屬性的JSON Object包裝。 對於這個結構,我們可以編寫類似於Jackson的通用反序列化器- 將對象的內部列表反序列化為一個更高級別的問題列表

示例Set反序列化器:

class InnerSetDeserializer extends JsonDeserializer<Set> implements ContextualDeserializer {

  private final JavaType propertyType;

  public InnerSetDeserializer() {
    this(null);
  }

  public InnerSetDeserializer(JavaType propertyType) {
    this.propertyType = propertyType;
  }

  @Override
  public Set deserialize(JsonParser p, DeserializationContext context) throws IOException {
    p.nextToken(); // SKIP START_OBJECT
    p.nextToken(); // SKIP any FIELD_NAME

    CollectionType collectionType = getCollectionType(context);
    List<Map<String, Object>> list = context.readValue(p, collectionType);

    p.nextToken(); // SKIP END_OBJECT

    return list.stream().map(Map::values).flatMap(Collection::stream).collect(Collectors.toSet());
  }

  private CollectionType getCollectionType(DeserializationContext context) {
    TypeFactory typeFactory = context.getTypeFactory();
    MapType mapType =
        typeFactory.constructMapType(
            Map.class, String.class, propertyType.getContentType().getRawClass());

    return typeFactory.constructCollectionType(List.class, mapType);
  }

  @Override
  public JsonDeserializer<?> createContextual(DeserializationContext context, BeanProperty property) {
    return new InnerSetDeserializer(property.getType());
  }
}

我們可以使用如下:

class Product {

  private String id;
  private String vendor;

  @JsonDeserialize(using = InnerSetDeserializer.class)
  private Set<Image> images;

  // getters, setters
}

應用示例:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class JsonApp {

  public static void main(String[] args) throws IOException {
    File jsonFile = new File("./resources/test.json");

    ObjectMapper mapper = new ObjectMapper();
    Product product = mapper.readValue(jsonFile, Product.class);
    System.out.println(product);
  }
}

上面的代碼打印:

Product{id='gid://mysite/Product/1853361520730', vendor='gadgetdown', images=[Image{originalSrc='https://cdn.something.com'}, Image{originalSrc='https://cdn.something.com'}]}

要從"node": { "originalSrc": "https:\\/\\/cdn.something.com" }解包Image "node": { "originalSrc": "https:\\/\\/cdn.something.com" }您只需使用@JsonRootName注釋即可

@JsonRootName(value = "node")
class Image {
    public String originalSrc;
}

但是從"images": { "edges": [{...}, {...}] }展開圖像集合"images": { "edges": [{...}, {...}] }有點復雜,需要使用自定義JsonDeserializer

class Product {
    public String id;
    public String vendor;

    @JsonDeserialize(using = ImageSetDeserializer.class)
    public Set<Image> images;
}


class ImageSetDeserializer extends JsonDeserializer<Set<Image>> {
    public Set<Image> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
        JsonNode node = mapper.readTree(jsonParser);
        return mapper.convertValue(node.get("edges").findValues("node"), new TypeReference<Set<Image>>() {});
    }
}

最后一個測試:

public class ProductTest {

    private final String source = "{\n" +
            "  \"id\": \"gid:\\/\\/mysite\\/Product\\/1853361520730\",\n" +
            "  \"vendor\": \"gadgetdown\",\n" +
            "  \"images\": {\n" +
            "    \"edges\": [\n" +
            "      {\n" +
            "        \"node\": {\n" +
            "          \"originalSrc\": \"https:\\/\\/cdn.something.com\"\n" +
            "        }\n" +
            "      },\n" +
            "      {\n" +
            "        \"node\": {\n" +
            "          \"originalSrc\": \"https:\\/\\/cdn.something.com\"\n" +
            "        }\n" +
            "      }\n" +
            "    ]\n" +
            "  }" +
            "}";

    @Test
    public void test() throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        Product product = mapper.readValue(source, Product.class);

        assertEquals(product.id, "gid://mysite/Product/1853361520730");
        assertEquals(product.vendor, "gadgetdown");
        assertNotNull(product.images);
        List<Image> images = new ArrayList<>(product.images);
        assertEquals(images.size(), 2);
        assertEquals(images.get(0).originalSrc, "https://cdn.something.com");
        assertEquals(images.get(1).originalSrc, "https://cdn.something.com");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM