我正在将ColdFusion 9中的REST/JSON服务转换为Spring-MVC 3.1应用程序。我使用了Spring提供的Jackson(1.9.5)和MappingJacksonJsonConverter,并使用CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES自定义ObjectMapper以命名字段。在Jackson反序列化中处理备用属性名称
我面临的问题是,我们的遗留服务产生'骆驼案件与UPPER案件与下划线'作为JSON属性名称。此JSON的消费者也使用ColdFusion编写,可能不太关心案例,但Jackson确实关心案例,并抛出UnrecognizedPropertyExceptions。
在研究了我可以从ObjectMapper - DeserializationConfig,DeserializerProvider等等获得的每一个设置后,我结束了一个非常混乱的黑客攻击,其中我解析了一个JSON树,用一个自定义的JsonGenerator输出它,字段名称,然后将其解析为对象。
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();
}
};
该解决方案似乎效率很低。有一个solution适用于地图的键,但我无法找到字段名称的类似解决方案。
另一种解决方案是使用两个setter,一个使用传统字段名称进行注释。命名策略具有扩展到忽略这些领域,这在我的情况是好的,因为对象映射器将不处理任何其他类与UPPER_UNDERSCORE策略:
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());
}
}
这是比以前更理想解决方案,但每个字段需要两个带注释的设置器 - 一个用于新格式,一个用于支持传统格式。
有没有人遇到过让杰克逊对反序列化字段名称不区分大小写的方法,或者为此接受字段名的多个别名?
'mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);'也应该有效。 – Daniel 2017-02-20 21:54:19