Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jackson-如何处理(反序列化)嵌套JSON?_Java_Json_Serialization_Jackson - Fatal编程技术网

Java Jackson-如何处理(反序列化)嵌套JSON?

Java Jackson-如何处理(反序列化)嵌套JSON?,java,json,serialization,jackson,Java,Json,Serialization,Jackson,我有一个Vendor对象,可以从一个“Vendor”json正确地反序列化,但我想将其反序列化为Vendor[],我就是不知道如何让Jackson合作。有什么提示吗?您的数据有问题,因为数组中有内部包装器对象。假定您的供应商对象设计用于处理id、名称、公司id,但这些多个对象中的每一个都包装在一个对象中,并具有单个属性供应商 我假设你使用的是杰克逊模型 如果是这样,那么有两件事需要考虑: 第一种是使用一个特殊的Jackson-config属性。Jackson-我认为,从1.9版开始,如果您使用的

我有一个Vendor对象,可以从一个“Vendor”json正确地反序列化,但我想将其反序列化为
Vendor[]
,我就是不知道如何让Jackson合作。有什么提示吗?

您的数据有问题,因为数组中有内部包装器对象。假定您的
供应商
对象设计用于处理
id
名称
公司id
,但这些多个对象中的每一个都包装在一个对象中,并具有单个属性
供应商

我假设你使用的是杰克逊模型

如果是这样,那么有两件事需要考虑:

第一种是使用一个特殊的Jackson-config属性。Jackson-我认为,从1.9版开始,如果您使用的是旧版本的Jackson,则可能无法提供此功能。它设计用于将结果包装在要丢弃的顶级单个属性对象中的情况

因此,请玩玩:

{
  vendors: [
    {
      vendor: {
        id: 367,
        name: "Kuhn-Pollich",
        company_id: 1,
      }
    },
    {
      vendor: {
        id: 374,
        name: "Sawayn-Hermann",
        company_id: 1,
      }
  }]
}
第二种是使用包装器对象。即使在丢弃外部包装器对象之后,仍然存在将
供应商
对象包装在单个属性对象中的问题。使用包装器解决此问题:

objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
类似地,您也可以定义一个包装类来处理外部对象,而不是使用
展开根值。假设您有正确的
供应商
供应商包装
对象,您可以定义:

class VendorWrapper
{
    Vendor vendor;

    // gettors, settors for vendor if you need them
}
最后,您可以使用Jackson将其解析为
JsonNodes
,丢弃外部节点,并针对
ArrayNode
中的每个
JsonNodes
,调用:

VendorsWrapper:
    vendors:
    [
        VendorWrapper
            vendor: Vendor,
        VendorWrapper:
            vendor: Vendor,
        ...
    ]

这可能会导致更少的代码,但它似乎并不比使用两个包装器更笨拙

这里是一个粗略但更具说明性的解决方案。我还不能把它归结为一个注释,但这似乎很有效。也不确定在大数据集上的性能

考虑到这一点:

mapper.readValue(node.get("vendor").getTextValue(), Vendor.class);
这些模型对象:

{
    "list": [
        {
            "wrapper": {
                "name": "Jack"
            }
        },
        {
            "wrapper": {
                "name": "Jane"
            }
        }
    ]
}

其中,杰克逊伏都教的实施方式如下:

public class InnerObject {
    @JsonProperty("name")
    public String name;
}

公共类SkipwrapPerObject反序列化器扩展JsonDeserializer实现
情境推理器{
私有类wrappedType;
私有字符串包装器密钥;
公共JsonDeserializer createContext(反序列化上下文ctxt,
BeanProperty属性)引发JsonMappingException{
SkipWrapperObject SkipWrapperObject=属性
.getAnnotation(SkipWrapperObject.class);
wrapperKey=skipWrapperObject.value();
JavaType collectionType=property.getType();
JavaType collectedType=collectionType.containedType(0);
wrappedType=collectedType.getRawClass();
归还这个;
}
@凌驾
公共对象反序列化(JsonParser解析器,反序列化上下文ctxt)
抛出IOException、JsonProcessingException{
ObjectMapper mapper=新的ObjectMapper();
ObjectNode ObjectNode=mapper.readTree(解析器);
JsonNode wrapped=objectNode.get(wrapperKey);
对象映射=mapIntoObject(已包装);
返回映射;
}
私有对象mapIntoObject(JsonNode节点)引发IOException,
JsonProcessingException{
JsonParser=node.traverse();
ObjectMapper mapper=新的ObjectMapper();
返回mapper.readValue(解析器,wrappedType);
}
}
希望这是有用的人

帕特里克 我会稍微改进一下你的解决方案

@覆盖
公共对象反序列化(JsonParser jp,反序列化上下文ctxt)
抛出IOException,JsonProcessingException{
ObjectNode ObjectNode=jp.readValueAsTree();
JsonNode wrapped=objectNode.get(wrapperKey);
JsonParser=node.traverse();
setCodec(jp.getCodec());
供应商映射=parser.readValueAs(Vendor.class);
返回映射;
}

它工作得更快:)

我参加聚会已经很晚了,但有一种方法是使用静态内部类来展开值:

public class SkipWrapperObjectDeserializer extends JsonDeserializer<Object> implements
        ContextualDeserializer {
    private Class<?> wrappedType;
    private String wrapperKey;

    public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
            BeanProperty property) throws JsonMappingException {
        SkipWrapperObject skipWrapperObject = property
                .getAnnotation(SkipWrapperObject.class);
        wrapperKey = skipWrapperObject.value();
        JavaType collectionType = property.getType();
        JavaType collectedType = collectionType.containedType(0);
        wrappedType = collectedType.getRawClass();
        return this;
    }

    @Override
    public Object deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode objectNode = mapper.readTree(parser);
        JsonNode wrapped = objectNode.get(wrapperKey);
        Object mapped = mapIntoObject(wrapped);
        return mapped;
    }

    private Object mapIntoObject(JsonNode node) throws IOException,
            JsonProcessingException {
        JsonParser parser = node.traverse();
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(parser, wrappedType);
    }
}

但是,使用
objectMapper.configure(SerializationConfig.Feature.UNWRAP\u ROOT\u值,true)可能更容易
@JsonRootName(“aName”)
结合使用,

这是无效的JSON<代码>供应商
的值是一个数组,该数组有一个对象,该对象有一个“供应商”属性,后面跟着一个裸露的顶级对象。i、 e.第二个
供应商
对象在数组中的单个对象中没有关联属性。此外,属性名不是字符串,它们需要在JSON中引用。我猜你输入的JSON是错的?一个好的答案取决于知道您实际使用的JSOn类型。抱歉,让我更正JSOn——现在应该修复您不能(或不想)拥有包含列表的供应商类?我是,但问题是供应商对象是嵌套的,作为数组中每个对象的“供应商”属性,而不是作为对象本身。这意味着我必须有一个带有VendorWrapper列表的Vendors类,其中每个VendorWrapper包含一个供应商。我现在有这个设置,但不太理想。谢谢,我就是这样做的,我只是希望有更好的方法。我会把它标记为正确的。我还希望看到一个解决方案,使用像“展开根”值这样的东西,只需要更深一层,但我认为这是不可能的。当然,另一种选择是使用自定义反序列化程序,只需添加钩子来查找您感兴趣的实际对象并放弃其他所有内容,或者使用Jackson树模型方法,抛弃顶级的
JsonNode
,并使用包装供应商的JsonNodes,调用
getTextValue
,并将其传递给
mapper.readValue
。Jackson确实给了你太多的选择。
mapIntoObject(JsonNode)
。。。因此,如果您想将
readValue
JsonNode
public class InnerObject {
    @JsonProperty("name")
    public String name;
}
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface SkipWrapperObject {
    String value();
}
public class SkipWrapperObjectDeserializer extends JsonDeserializer<Object> implements
        ContextualDeserializer {
    private Class<?> wrappedType;
    private String wrapperKey;

    public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
            BeanProperty property) throws JsonMappingException {
        SkipWrapperObject skipWrapperObject = property
                .getAnnotation(SkipWrapperObject.class);
        wrapperKey = skipWrapperObject.value();
        JavaType collectionType = property.getType();
        JavaType collectedType = collectionType.containedType(0);
        wrappedType = collectedType.getRawClass();
        return this;
    }

    @Override
    public Object deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode objectNode = mapper.readTree(parser);
        JsonNode wrapped = objectNode.get(wrapperKey);
        Object mapped = mapIntoObject(wrapped);
        return mapped;
    }

    private Object mapIntoObject(JsonNode node) throws IOException,
            JsonProcessingException {
        JsonParser parser = node.traverse();
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(parser, wrappedType);
    }
}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

class Scratch {
    private final String aString;
    private final String bString;
    private final String cString;
    private final static String jsonString;

    static {
        jsonString = "{\n" +
                "  \"wrap\" : {\n" +
                "    \"A\": \"foo\",\n" +
                "    \"B\": \"bar\",\n" +
                "    \"C\": \"baz\"\n" +
                "  }\n" +
                "}";
    }

    @JsonCreator
    Scratch(@JsonProperty("A") String aString,
            @JsonProperty("B") String bString,
            @JsonProperty("C") String cString) {
        this.aString = aString;
        this.bString = bString;
        this.cString = cString;
    }

    @Override
    public String toString() {
        return "Scratch{" +
                "aString='" + aString + '\'' +
                ", bString='" + bString + '\'' +
                ", cString='" + cString + '\'' +
                '}';
    }

    public static class JsonDeserializer {
        private final Scratch scratch;

        @JsonCreator
        public JsonDeserializer(@JsonProperty("wrap") Scratch scratch) {
            this.scratch = scratch;
        }

        public Scratch getScratch() {
            return scratch;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Scratch scratch = objectMapper.readValue(jsonString, Scratch.JsonDeserializer.class).getScratch();
        System.out.println(scratch.toString());
    }
}