Tôi đang làm việc để chuyển đổi dịch vụ REST/JSON từ Coldfusion 9 sang ứng dụng Spring-MVC 3.1. Tôi đang sử dụng Jackson (1.9.5) và MappingJacksonJsonConverter mà Spring cung cấp, và đang tùy chỉnh ObjectMapper để đặt tên các trường bằng CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES.Xử lý các tên thuộc tính thay thế trong Jackson Deserialization
Sự cố tôi đang gặp phải là dịch vụ kế thừa của chúng tôi tạo 'trường hợp lạc đà tới trường hợp UPPER có dấu gạch dưới' làm tên thuộc tính json. Người tiêu dùng của JSON này, cũng được viết bằng ColdFusion, có thể quan tâm ít hơn về trường hợp, nhưng Jackson quan tâm đến trường hợp và ném UnrecognizedPropertyExceptions.
Sau khi xem xét mọi thiết lập mà tôi có thể tiếp cận từ ObjectMapper - DeserializationConfig, DeserializerProvider, v.v., tôi đã kết thúc với một hack rất lộn xộn, trong đó tôi phân tích cú pháp thành cây JSON, xuất nó với một JsonGenerator tùy chỉnh tên trường, và sau đó phân tích cú pháp nó trở thành một đối tượng.
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();
}
};
Giải pháp này có vẻ rất không hiệu quả. Có solution hoạt động cho các khóa của bản đồ, nhưng tôi không thể tìm thấy giải pháp tương tự cho tên trường.
Giải pháp thay thế là có hai bộ định vị, một giải pháp được chú thích với tên trường cũ. Chiến lược đặt tên đã được mở rộng để bỏ qua các lĩnh vực này, mà trong hoàn cảnh của tôi là tốt vì đối tượng mapper sẽ không được đối phó với bất kỳ lớp học khác với một chiến lược 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());
}
}
Đây là chi tiết lý tưởng hơn so với trước đây giải pháp, nhưng sẽ yêu cầu hai bộ giải mã có chú thích cho mọi trường - một cho định dạng mới, một để hỗ trợ định dạng cũ.
Có ai đi qua một cách để làm cho Jackson không phân biệt chữ hoa chữ thường hay không, hoặc cho vấn đề đó chấp nhận nhiều bí danh cho một tên trường?
'mapper.enable (MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);' cũng sẽ hoạt động. – Daniel