抽象
我使用JsonPath选择JSON文件的一部分并将其反序列化为POJO。这适用于字符串,但我无法弄清楚如何让Jackson将三元素数组反序列化为我自己的类(Vector3d)的单个实例。 Jackson文档中的所有示例似乎都涉及将JSON中的元素转换为恰好一个Java对象。有什么想法吗?
文档说明
如果您将JsonPath配置为使用JacksonMappingProvider,您甚至可以将JsonPath输出直接映射到POJO中。
Book book = JsonPath.parse(json).read(" $。store.book [0]",Book.class);
但是我无法让它发挥作用。
我尝试了什么
我的Vector3d
类如下所示(注意@JsonCreator
构造函数):
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]);
}
}
对于此示例(我使用的实际文件更复杂):
{
type: "viper",
location: [
20,
173,
153
]
}
我可以获得这个位置'矢量作为一个三元素数组如下(这段代码过于冗长,但只是为了保持下一步小):
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()调用期间会遇到异常:
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
构建虽然对[{1}}进行反序列化有效,但添加了int[]
构造函数@JsonCreator
,但仍无法正常工作。有任何想法吗?
答案 0 :(得分:2)
不知道内部非静态类是否存在问题。这对我有用:
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));
}
}
答案 1 :(得分:1)
事实证明存在两个问题。首先,我写的地方
configuration.mappingProvider(mappingProvider);
我应该写:
configuration = configuration.mappingProvider(mappingProvider);
其次,我无法使注释工作,但我确实使用自定义反序列化器进行管理。由于我更喜欢我的值类不依赖于特定的JSON序列化格式,因此我将其定义为mixin:
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)
有效。不幸的是,这需要&gt;像以前一样解析修复JSON文件的时间长度是10倍。如果有人知道更好的解决方案,请告诉我。
答案 2 :(得分:0)
映射您的对象属性&#34; location&#34;到构造函数变量使用@JsonProperty:
@JsonCreator
public Vector3d(@JsonProperty("location") Integer[] values) {
this(values[0], values[1], values[2]);
}
或命名构造函数变量,与json对象中的prop相同(&#39; location&#39;)
@JsonCreator
public Vector3d(Integer[] location) {
this(location[0], location[1], location[2]);
}
我也不确定int []是否可以序列化,所以我用了Integer []