Java 使用Jackson反序列化字符串化(引号括起)嵌套对象
我正在使用一个“RESTful”服务(通过RestTemplate),该服务生成JSON,如下所示:Java 使用Jackson反序列化字符串化(引号括起)嵌套对象,java,json,jackson,Java,Json,Jackson,我正在使用一个“RESTful”服务(通过RestTemplate),该服务生成JSON,如下所示: { "id": "abcd1234", "name": "test", "connections": { "default": "http://foo.com/api/", "dev": "http://dev.foo.com/api/v2" }, "settings": { "foo": "{\n \"fo
{
"id": "abcd1234",
"name": "test",
"connections": {
"default": "http://foo.com/api/",
"dev": "http://dev.foo.com/api/v2"
},
"settings": {
"foo": "{\n \"fooId\": 1, \"token\": \"abc\"}",
"bar": "{\"barId\": 2, \"accountId\": \"d7cj3\"}"
}
}
public class QuotedObjectDeserializer<T> extends JsonDeserializer<T> implements ContextualDeserializer {
private Class<?> targetType;
private ObjectMapper mapper;
public QuotedObjectDeserializer(Class<?> targetType, ObjectMapper mapper) {
this.targetType = targetType;
this.mapper = mapper;
}
@Override
public JsonDeserializer<T> createContextual(DeserializationContext context, BeanProperty property) {
this.targetType = property.getType().containedType(1).getRawClass();
return new QuotedObjectDeserializer<T>(this.targetType, this.mapper);
}
@Override
public T deserialize(JsonParser jp, DeserializationContext context) throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
String text = node.toString();
String trimmed = text.substring(1, text.length() - 1);
trimmed = trimmed.replace("\\", "");
trimmed = trimmed.replace("\n", "");
JsonNode obj = this.mapper.readTree(trimmed);
return this.mapper.convertValue(obj, this.mapper.getTypeFactory().constructType(this.targetType));
}
}
请注意settings.foo
和settings.bar
值,它们会导致反序列化问题。我希望能够反序列化为对象(例如,settings.getFoo().getFooId()
,settings.getFoo().getToken()
)
我能够通过自定义反序列化器专门为Foo
的一个实例解决这个问题:
public class FooDeserializer extends JsonDeserializer<Foo> {
@Override
public Foo deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
JsonNode node = jp.getCodec().readTree(jp);
String text = node.toString();
String trimmed = text.substring(1, text.length() - 1);
trimmed = trimmed.replace("\\", "");
trimmed = trimmed.replace("\n", "");
ObjectMapper mapper = new ObjectMapper();
JsonNode obj = mapper.readTree(trimmed);
Foo result = mapper.convertValue(obj, Foo.class);
return result;
}
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Settings {
@JsonDeserialize(using = FooDeserializer.class)
private Foo foo;
private Bar bar;
}
现在我不确定如何实际使用反序列化程序,因为用@jsondeselliate(使用=quoteObjectDeserializer.class)注释Settings.Foo
显然不起作用
有没有一种方法可以注释属性以使用通用的自定义反序列化程序?或者,也许更可能的是,是否有一种方法可以配置默认的反序列化程序来处理示例JSON中返回的stringy对象
Edit:这里的问题是将settings.foo
和settings.bar
反序列化为对象。JSON表示法将这些对象包装在引号中(并被转义序列污染),因此它们被反序列化为字符串
对不起,这里的代码太长了。这里有很多快捷方式(没有封装;将e添加到default以避免关键字等),但目的就在这里
模型类:
package com.odwyer.rian.test;
import java.io.IOException;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Model {
public String id;
public String name;
public Connections connections;
public Settings settings;
public static class Connections {
public String defaulte;
public String dev;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
public static class Foo {
public Foo () {}
@JsonCreator
public static Foo create(String str) throws JsonParseException, JsonMappingException, IOException {
return (new ObjectMapper()).readValue(str, Foo.class);
}
public Integer fooId;
public String token;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
public static class Bar {
public Bar() {}
@JsonCreator
public static Bar create(String str) throws JsonParseException, JsonMappingException, IOException {
return (new ObjectMapper()).readValue(str, Bar.class);
}
public Integer barId;
public String accountId;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
public static class Settings {
public Foo foo;
public Bar bar;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
呼叫者:
package com.odwyer.rian.test;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestClass {
private static ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
Scanner file = new Scanner(new File("test.json"));
String jsonStr = file.useDelimiter("\\Z").next();
Model model = objectMapper.readValue(jsonStr, Model.class);
System.out.println(model.toString());
}
}
结果(太麻烦了,无法格式化,但都在那里!):
com.odwyer.rian.test。Model@190083e[id=abcd1234,name=test,connections=com.odwyer.rian.test.Model$Connections@170d1f3f[默认=$Settings@5e7e6ceb[foo=com.odwyer.rian.test.Model$Foo@3e20e8c4[fooId=1,token=abc],bar=com.odwyer.rian.test.Model$Bar@6291bbb9[barId=2,accountId=d7cj3]]
Ted和他的帖子()提供的关键是@JsonCreator
注释您是否尝试创建Json数据的POJO对象并使用jackson检索它?如果您先创建POJO,然后调用settings.getFoo().getFooId()会的easy@Sudnep是。请注意settings.foo和settings.bar值,它们会导致反序列化问题(用引号、反斜杠等括起来)。使用@JsonCreator
和创建(字符串str)
方法确实正确解析了JSON,但此解决方案仍然需要每种类型的实现。实际上,我有几十个设置(foo
,bar
,baz
,batz
,等等),理想情况下,解决方案不需要对这些类型中的每一种进行修改。您应该能够创建一个超类并将create函数放在其中。我考虑过这一点,但我不确定如何在超类的create
方法中构造给定子类型的实例。我有点不喜欢使用newObjectMapper()
在用@JsonCreator
注释的静态创建方法中。这意味着用于读取负载的对象映射器与用于读取负载内部部分的对象映射器不同。如果您没有配置,这可能不是问题,但许多人可能有一个他们希望在这两个lo中使用的单例对象映射器阳离子。没有办法获取原始的objectMapper并重用它吗?@gaoangg这是我在回答中提到的众多快捷方式之一。你当然是对的,单个实例更好,无论是通过单实例还是工厂模式注入或访问