我正在消费" RESTful" service(通过RestTemplate)生成JSON,如下所示:
{
"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\"}"
}
}
请注意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;
}
但是,现在如果我想反序列化settings.bar
,我需要实现另一个自定义反序列化器。所以我实现了一个通用的反序列化器,如下所示:
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
@JsonDeserialize(using = QuotedObjectDeserializer.class)
显然不起作用。
有没有办法注释属性以使用通用的自定义反序列化器?或者,或许更有可能的是,有没有办法配置默认的反序列化器来处理我的示例JSON中返回的 stringy 对象?
修改:此处的问题是将settings.foo
和settings.bar
反序列化为对象。 JSON表示将这些对象包装在引号中(并使用转义序列进行污染),因此它们被反序列化为Strings
。
答案 0 :(得分:3)
对此处代码的长度感到抱歉。这里有很多快捷方式(没有封装;添加e以默认以避免关键字等)但意图是那里 型号类:
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,名字=测试,连接= com.odwyer.rian.test.Model $连接@ 170d1f3f [defaulte = http://foo.com/api/,dev=http://dev.foo.com/api/v2],settings=com.odwyer.rian.test.Model $设置@ 5e7e6ceb [富= com.odwyer.rian.test.Model$Foo@3e20e8c4 [fooId = 1,标记= ABC],棒= com.odwyer.rian.test.Model $酒吧@ 6291bbb9 [barId = 2,帐户ID = d7cj3]]] < / p>
Ted和他的帖子(https://stackoverflow.com/a/8369322/2960707)提供的关键是@JsonCreator
注释