使用Jackson

时间:2016-06-23 19:05:49

标签: java json jackson

我正在消费" 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.foosettings.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.foosettings.bar反序列化为对象。 JSON表示将这些对象包装在引号中(并使用转义序列进行污染),因此它们被反序列化为Strings

1 个答案:

答案 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注释