我有一个类似于这个的豆子:
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有效负载中的所有数组项都以这种edges
和node
表示形式包装。
答案 0 :(得分:3)
因此images
不是set
,而是其中包含JSONObject
列表的edges
public class Images {
private List<Edge> edges;
}
每个Edge
包含Node
对象
public class Edge {
private Node node;
}
每个Node
具有单个字符串属性originalSrc
public class Node {
private String originalSrc;
}
答案 1 :(得分:1)
如果每个列表都具有如下结构:
{
"images": {
"edges": [
{
"node": {
"entry": "entry-value"
}
}
]
}
}
每个列表都是具有JSON Object
属性的edges
,并且数组中的每个元素都由具有JSON Object
属性的node
包装。对于这种结构,我们可以编写类似于Jackson - deserialize inner list of objects to list of one higher level问题中的通用解串器。
示例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'}]}
答案 2 :(得分:0)
要从Image
中解包"node": { "originalSrc": "https:\/\/cdn.something.com" }
,您只需使用@JsonRootName
批注
@JsonRootName(value = "node")
class Image {
public String originalSrc;
}
但是从"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");
}
}