使用JacksonDeserializer将JSON的一部分保留为String

时间:2019-07-04 08:38:51

标签: java json jackson deserialization jackson-databind

我想保留JSON的一部分作为String值。 据我所知,Annotations是没有办法的,但是我找不到一种方法来获取完整的Object / Array值作为String。

有一种解决方法,该方法通过将其作为对象读取并使用Jackson的ObjectMapper立即将其写回字符串的方式起作用。 您可以想象,对于大型JSON,这是一个可怕的解决方案。

public class DeserializeTest {

    private static ObjectMapper mapper;

    public static void main(String[] args) throws IOException {
        mapper = Jackson2ObjectMapperBuilder.json().build();
        mapper.findAndRegisterModules();

        SimpleModule module = new SimpleModule();
        module.addDeserializer(TestClassWrapper.class, new TestDeserializer());
        mapper.registerModule(module);

        String json = "{\"name\":\"testprop\", \"data\":[{\"prop\":\"test\"},{\"prop\":\"test1\"},{\"prop\":\"test2\"}]}";
        TestClassWrapper t = mapper.readValue(json, TestClassWrapper.class);

        // later in program, when i know the expected class
        TestClass o = unwrap(t, new TypeReference<ArrayList<Test2>>() {});
    }

    public static class TestClassWrapper {
        String name;
        String data;

        // removed getter and setter
    }

    public static class TestClass {
        String name;
        List<Test2> data;
        // removed getter and setter
    }

    public static class Test2 {
        String prop;
        // removed getter and setter
    }

    public static class TestDeserializer extends JsonDeserializer<TestClassWrapper> {

        @Override
        public TestClassWrapper deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

            TestClassWrapper t = new TestClassWrapper();
            String key = p.getCurrentName();
            if (key == null) {
                p.nextToken();
                key = p.getCurrentName();
            }
            for (; key != null; key = p.nextFieldName()) {
                p.nextToken();
                switch (key) {
                    case "name":
                        t.name = p.getValueAsString();
                        break;
                    case "data":
                        // what i tried: 
                        System.out.println(p.getText()); // [
                        System.out.println(p.getValueAsString()); // NULL
                        System.out.println(p.getCurrentValue()); //NULL
                        System.out.println(p.getCurrentToken()); // [ TOKEN
                        System.out.println(p.getParsingContext().getCurrentValue()); // NULL
                        System.out.println(p.getParsingContext().toString()); // [0]
                        System.out.println(p.getEmbeddedObject()); // NULL
                        System.out.println(p.getTextCharacters()); // [
                        try {
                            System.out.println(ctxt.readValue(p, String.class)); // MismatchedInputException
                        } catch (MismatchedInputException e){}

                        // The only way i could make it work.
                        // Parse to a object and write it back as string.
                        StringBuilder sb = new StringBuilder();
                        Iterator<Object> it = p.readValuesAs(Object.class);
                        while (it.hasNext()) {
                            sb.append(mapper.writeValueAsString(it.next()));
                            sb.append(it.hasNext() ? "," : "");
                        }
                        t.data = p.getCurrentToken() == JsonToken.END_ARRAY ? "[" + sb.toString() + "]" : sb.toString();
                        break;
                }
            }

            return t;
        }
    }

    public static TestClass unwrap(TestClassWrapper t, TypeReference targetClass) throws IOException {
        TestClass o = new TestClass();
        o.name = t.name;
        o.data = mapper.readValue(t.data, targetClass);
        return o;
    }
}

我怎样才能告诉JsonParser对象给我当前值的字符串?

(对于data,应为:“ [{"prop":"test"}, {"prop":"test1"}, {"prop":"test2"}]”)

0 个答案:

没有答案