文摘
我使用JsonPath选择JSON文件的一部分,并将其反序列化为POJO。这对于String来说很好,但我不知道如何让Jackson将一个三元素数组反序列化为我自己类的一个实例(Vector3d)。Jackson文档中的所有示例似乎都涉及到JSON中的元素,这些元素正被转换成一个Java对象。有什么想法吗?
文档说什么,
如果将JsonPath配置为使用JacksonMappingProvider,甚至可以将JsonPath输出直接映射到POJO中。 图书= JsonPath.parse(json).read("$.store.book",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
]
}我可以将“location”向量作为一个三元素数组,如下所示(这段代码过于冗长,但只是为了保持下一步的小规模):
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可以工作,但是int[]结构不能工作,并添加了采用int[]的@JsonCreator构造函数。有什么想法吗?
发布于 2015-04-09 16:19:42
不知道内部非静态类是否有问题。这对我来说很管用:
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));
}
}发布于 2015-04-07 00:00:58
结果发现有两个问题。首先,我写的地方
configuration.mappingProvider(mappingProvider);我应该写的是:
configuration = configuration.mappingProvider(mappingProvider);第二,我无法让注释正常工作,但我确实使用了自定义反序列化器。由于我希望我的值类不被绑定到特定的JSON序列化格式,所以我将其定义为一个混合体:
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倍。如果有人知道更好的解决办法,请告诉我。
发布于 2015-04-06 13:10:09
要将对象属性“位置”映射到构造函数变量,请使用@JsonProperty:
@JsonCreator
public Vector3d(@JsonProperty("location") Integer[] values) {
this(values[0], values[1], values[2]);
}或命名构造函数变量,与json对象(‘location’)中的支柱变量相同。
@JsonCreator
public Vector3d(Integer[] location) {
this(location[0], location[1], location[2]);
}另外,我也不确定int[]是否可以序列化,所以我使用了Integer[]
https://stackoverflow.com/questions/29471589
复制相似问题