首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JsonPath/Jackson:如何将JSON数组反序列化为单个对象("[1,2,3]“-> Vector3d实例)?

JsonPath/Jackson:如何将JSON数组反序列化为单个对象("[1,2,3]“-> Vector3d实例)?
EN

Stack Overflow用户
提问于 2015-04-06 12:45:03
回答 3查看 9.3K关注 0票数 2

文摘

我使用JsonPath选择JSON文件的一部分,并将其反序列化为POJO。这对于String来说很好,但我不知道如何让Jackson将一个三元素数组反序列化为我自己类的一个实例(Vector3d)。Jackson文档中的所有示例似乎都涉及到JSON中的元素,这些元素正被转换成一个Java对象。有什么想法吗?

文档说什么,

JsonPath文档提到

如果将JsonPath配置为使用JacksonMappingProvider,甚至可以将JsonPath输出直接映射到POJO中。 图书= JsonPath.parse(json).read("$.store.book",Book.class);

但我不能让它起作用。

我试过什么

我的Vector3d类如下(注意@JsonCreator构造函数):

代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonCreator;

public final class Vector3d {
    private final int x, y, z;

    public Vector3d(int x, int y, int z) { 
        this.x = x; this.y = y; this.z = z;
    }

    @JsonCreator
    public Vector3d(int[] values) { 
        this(values[0], values[1], values[2]); 
    }
}

对于这个例子(我使用的实际文件更复杂):

代码语言:javascript
复制
{
    type: "viper",
    location: [
        20,
        173,
        153
    ]
}

我可以将“location”向量作为一个三元素数组,如下所示(这段代码过于冗长,但只是为了保持下一步的小规模):

代码语言:javascript
复制
package main;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.internal.JsonReader;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;

import java.util.Arrays;

public class Tester {
    public static void main(String[] args) throws Exception {
        Configuration configuration = Configuration.defaultConfiguration();
        MappingProvider mappingProvider = new JacksonMappingProvider();
        configuration.mappingProvider(mappingProvider);
        JsonReader jsonReader = new JsonReader(configuration);
        DocumentContext documentContext = jsonReader.parse("{\n" +
                "\ttype: \"viper\",\n" +
                "\tlocation: [\n" +
                "\t\t20,\n" +
                "\t\t173,\n" +
                "\t\t153\n" +
                "\t]\n" +
                "}");
        int[] data = documentContext.read("$.location", int[].class);

        System.out.println(Arrays.toString(data));
    }
}

但是,如果在最后一行中使用Vector3d而不是int[],则在read()调用期间会得到一个异常:

代码语言:javascript
复制
java.lang.RuntimeException: Invalid or non Implemented status createArray() in class net.minidev.json.writer.BeansMapper$Bean
    at net.minidev.json.writer.JsonReaderI.createArray(JsonReaderI.java:98)
    at net.minidev.json.parser.JSONParserBase.readArray(JSONParserBase.java:235)
    at net.minidev.json.parser.JSONParserBase.readFirst(JSONParserBase.java:298)
    at net.minidev.json.parser.JSONParserBase.parse(JSONParserBase.java:154)
    at net.minidev.json.parser.JSONParserString.parse(JSONParserString.java:58)
    at net.minidev.json.parser.JSONParser.parse(JSONParser.java:261)
    at net.minidev.json.JSONValue.parse(JSONValue.java:206)
    at com.jayway.jsonpath.spi.mapper.JsonSmartMappingProvider.map(JsonSmartMappingProvider.java:86)
    at com.jayway.jsonpath.internal.JsonReader.convert(JsonReader.java:174)
    at com.jayway.jsonpath.internal.JsonReader.read(JsonReader.java:140)
    at main.Tester.main(Tester.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

我感到困惑的是,尽管反序列化到Vector3d可以工作,但是int[]结构不能工作,并添加了采用int[]@JsonCreator构造函数。有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-04-09 16:19:42

不知道内部非静态类是否有问题。这对我来说很管用:

代码语言:javascript
复制
public class VectorTest {

    private static final String JSON = "{\n" +
            "    \"type\": \"viper\",\n" +
            "    \"location\": [\n" +
            "        20,\n" +
            "        173,\n" +
            "        153\n" +
            "    ]\n" +
            "}";

    static {
        Configuration.setDefaults(new Configuration.Defaults() {
            private final JsonProvider jsonProvider = new JacksonJsonProvider();
            private final MappingProvider mappingProvider = new JacksonMappingProvider();
            private final Set<Option> options = EnumSet.noneOf(Option.class);

            public JsonProvider jsonProvider() {
                return jsonProvider;
            }

            @Override
            public MappingProvider mappingProvider() {
                return mappingProvider;
            }

            @Override
            public Set<Option> options() {
                return options;
            }
        });
    }

    public static final class Vector3d {
        public final int x, y, z;

        @JsonCreator
        public Vector3d(int[] values) {
            this.x = values[0];
            this.y = values[1];
            this.z = values[2];
        }
    }

    @Test
    public void a_test() {
        Vector3d vector = JsonPath.parse(JSON).read("$.location", Vector3d.class);

        Assert.assertThat(vector.x, is(20));
        Assert.assertThat(vector.y, is(173));
        Assert.assertThat(vector.z, is(153));
    }
}
票数 2
EN

Stack Overflow用户

发布于 2015-04-07 00:00:58

结果发现有两个问题。首先,我写的地方

代码语言:javascript
复制
configuration.mappingProvider(mappingProvider);

我应该写的是:

代码语言:javascript
复制
configuration = configuration.mappingProvider(mappingProvider);

第二,我无法让注释正常工作,但我确实使用了自定义反序列化器。由于我希望我的值类不被绑定到特定的JSON序列化格式,所以我将其定义为一个混合体:

代码语言:javascript
复制
class JsonReaders {
    private JsonReaders() { } 

    static class MixinModule extends SimpleModule {
        static class Vector3dDeserializer extends JsonDeserializer<Vector3d> {
            @Override
            public Vector3d deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
                int[] values = jp.readValueAs(int[].class);
                return new Vector3d(values[0], values[1], values[2]);
            }
        }

        @Override
        public void setupModule(SetupContext context) {
            super.setupModule(context);
            SimpleDeserializers deserializers = new SimpleDeserializers();
            deserializers.addDeserializer(Vector3d.class, new Vector3dDeserializer());
            context.addDeserializers(deserializers);
        }
    }

    public static Configuration createConfiguration() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new MixinModule());
        MappingProvider mappingProvider = new JacksonMappingProvider(objectMapper);
        Configuration configuration = Configuration.defaultConfiguration()
                .mappingProvider(mappingProvider);
        return configuration;
    }

    public static JsonReader createReader() {
        JsonReader result = new JsonReader(createConfiguration());
        return result;
    }
}

使用上面定义的JsonReader,代码jsonReader.read("$.location", Vector3d.class)可以工作。不幸的是,解析修复JSON文件所需的时间是以前的>10倍。如果有人知道更好的解决办法,请告诉我。

票数 1
EN

Stack Overflow用户

发布于 2015-04-06 13:10:09

要将对象属性“位置”映射到构造函数变量,请使用@JsonProperty:

代码语言:javascript
复制
@JsonCreator
public Vector3d(@JsonProperty("location") Integer[] values) {
    this(values[0], values[1], values[2]);
}

或命名构造函数变量,与json对象(‘location’)中的支柱变量相同。

代码语言:javascript
复制
@JsonCreator
public Vector3d(Integer[] location) {
    this(location[0], location[1], location[2]);
}

另外,我也不确定int[]是否可以序列化,所以我使用了Integer[]

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29471589

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档