处理杰克逊反序列化中的备用属性名称 [英] Handling alternate property names in Jackson Deserialization

查看:449
本文介绍了处理杰克逊反序列化中的备用属性名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力将REST / JSON服务从Coldfusion 9转换为Spring-MVC 3.1应用程序。我正在使用Jackson提供的Jackson(1.9.5)和MappingJacksonJsonConverter,并使用CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES自定义ObjectMapper以命名字段。

I am working on converting a REST/JSON service from Coldfusion 9 to a Spring-MVC 3.1 application. I am using Jackson (1.9.5) and the MappingJacksonJsonConverter that Spring provides, and am customizing the ObjectMapper to name fields with CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES.

我面临的问题是我们的问题遗留服务生成'带有下划线的UPPER案例的驼峰案例'作为json属性名称。这个JSON的消费者,也用ColdFusion编写,可能不关心案例,但杰克逊确实关心案例,并抛出UnrecognizedPropertyExceptions。

The problem I am facing is that our legacy service produces 'camel case to UPPER case with underscores' as json property names. The consumers of this JSON, also written in ColdFusion, could care less about case, but Jackson does care about case, and throws UnrecognizedPropertyExceptions.

在查看几乎所有设置之后我可以从ObjectMapper - DeserializationConfig,DeserializerProvider等处获得,我最终得到了一个非常混乱的黑客,我解析为JSON树,使用自定义JsonGenerator输出它,降低了字段名称的大小,然后将其解析为对象。

After looking into just about every setting I could reach from ObjectMapper - DeserializationConfig, DeserializerProvider, etc, I ended up with a very messy hack in which I parse to a JSON tree, output it with a custom JsonGenerator that lower cases the field names, and then parses it back in as an object.

MappingJacksonHttpMessageConverter mc = new MappingJacksonHttpMessageConverter() {
    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return this.getObjectMapper().readValue(translateToLowerCaseKeys(inputMessage.getBody()), getJavaType(clazz));
    }

    private byte[] translateToLowerCaseKeys(InputStream messageBody) throws IOException {
        StringWriter sw = new StringWriter();
        JsonGenerator lowerCaseFieldNameGenerator = new JsonGeneratorDelegate(this.getObjectMapper().getJsonFactory().createJsonGenerator(sw)) {
            @Override
            public void writeFieldName(String name) throws IOException, org.codehaus.jackson.JsonGenerationException {
                delegate.writeFieldName(name.toLowerCase());
            };
        };
        this.getObjectMapper().writeTree(lowerCaseFieldNameGenerator, this.getObjectMapper().readTree(messageBody));
        lowerCaseFieldNameGenerator.close();
        return sw.getBuffer().toString().getBytes();
    }
};

此解决方案效率非常低。有一个解决方案适用于地图的键,但我无法找到类似的字段名称解决方案。

This solution seems very inefficient. There is a solution that works for keys of a map, but I was unable to find a similar solution for field names.

另一种解决方案是使用两个setter,其中一个使用旧字段名称进行注释。命名策略必须扩展为忽略这些字段,这在我的情况下很好,因为对象映射器不会处理任何其他具有UPPER_UNDERSCORE策略的类:

An alternative solution is to have two setters, one annotated with the legacy field name. The naming strategy has to be extended to ignore these fields, which in my situation is fine since the object mapper won't be dealing with any other classes with an UPPER_UNDERSCORE strategy:

public class JsonNamingTest {
    public static class CaseInsensitive extends LowerCaseWithUnderscoresStrategy {
        public String translate(String in) {
            return (in.toUpperCase().equals(in) ? in : super.translate(in));
        }
    }

    public static class A {
        private String testField;
        public String getTestField() {
            return testField;
        }
        public void setTestField(String field) {
            this.testField = field;
        }
        @JsonProperty("TEST_FIELD")
        public void setFieldAlternate(String field) {
            this.testField = field;
        }
    }

    @Test
    public void something() throws Exception {
        A test = new A();
        test.setTestField("test");
        ObjectMapper mapper = new ObjectMapper().setPropertyNamingStrategy(new CaseInsensitive());
        assertEquals("{\"test_field\":\"test\"}", mapper.writeValueAsString(test));
        assertEquals("test", mapper.readValue("{\"test_field\":\"test\"}", A.class).getTestField());
        assertEquals("test", mapper.readValue("{\"TEST_FIELD\":\"test\"}", A.class).getTestField());
    }
}

这比以前的解决方案更理想,但是每个字段都需要两个带注释的setter - 一个用于新格式,一个用于支持旧格式。

This is more ideal than the previous solution, but would require two annotated setters for every field - one for the new format, one to support the legacy format.

有没有人遇到过让杰克逊对反序列化不区分大小写的方法字段名称,或者就此而言接受字段名称的多个别名?

Has anyone come across a way to make Jackson case-insensitive for deserializing field names, or for that matter accept multiple aliases for a field name?

推荐答案

这已经在Jackson 2.5.0中修复。

This has been fixed as of Jackson 2.5.0.

ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

这篇关于处理杰克逊反序列化中的备用属性名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆