How can I loosen up the naming strategy when deserializing using Jackson? How can I loosen up the naming strategy when deserializing using Jackson? json json

How can I loosen up the naming strategy when deserializing using Jackson?


@JsonProperty overrides any PropertyNamingStrategy in fasterxml since version 2.4.0. However, yet-to-be-released version 2.7.0 will provide a feature to allow you to opt back in to the old behavior. There is also an unimplemented suggestion to toggle this at the per-annotation level, but that would not really help you.

It appears that Codehaus does apply the PropertyNamingStrategy on top of the @JsonProperty values when mapping, although I can't find any clear docs on that. This appears to have been the behavior in fasterxml before 2.4.0 as well. Here is another example of someone noticing the same difference in behavior.


Although the solution provided by SkinnyJ is perfect for your problem, but if you can't wait till 2.7 is released, you can apply the below hack to get around the problem.

The idea is to transform the incoming JSON to match the attributes in your bean definition. Below code does that. Following points should be noted:

  1. If you are dealing with nested structures, you will have to implement a recursive function to achieve this transformation.
  2. There is a little overhead involved in doing the transformation.

Code:

public class JSONTest extends Assert {    @JsonIgnoreProperties(ignoreUnknown = true)    public static class Product {        @JsonProperty(value = "variationId")        private String variantId;        @JsonProperty(value = "price_text")        private String priceText;        @JsonProperty(value = "listPrice")        public String listPrice;        @JsonProperty(value = "PRODUCT_NAME")        public String name;        @JsonProperty(value = "Product_Desc")        public String description;    }    private static final String VALID_PRODUCT_JSON =            "{ \"list_price\": 289," +             " \"price_text\": \"269.00\"," +             " \"variation_id\": \"EUR\"," +             " \"product_name\": \"Product\"," +             " \"product_desc\": \"Test\"" +            "}";    @Test    public void testDeserialization() throws IOException {        ObjectMapper mapper = new ObjectMapper();        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);        //Capture the original JSON in org.json.JSONObject        JSONObject obj = new JSONObject(VALID_PRODUCT_JSON);        JSONArray keys = obj.names();        //New json object to be created using property names defined in bean        JSONObject matchingJson = new JSONObject();        //Map of lowercased key to original keys in incoming json. eg: Prod_id > prodid        Map<String, String> jsonMappings = new LinkedHashMap<String, String>();        for (int i = 0; i < keys.length(); i++) {            String key = lowerCaseWithoutUnderScore(keys.getString(i));            String value = keys.getString(i);            jsonMappings.put(key, value);        }        /*         * Iternate all jsonproperty beans and create new json         * such that keys in json map to that defined in bean         */        Field[] fields = Product.class.getDeclaredFields();        for (Field field : fields) {            JsonProperty prop = field.getAnnotation(JsonProperty.class);            String propNameInBean = prop.value();            String keyToLook = lowerCaseWithoutUnderScore(propNameInBean);            String keyInJson = jsonMappings.get(keyToLook);            matchingJson.put(propNameInBean, obj.get(keyInJson));        }        String json = matchingJson.toString();        System.out.println(json);        //Pass the matching json to Object mapper        Product product = mapper.readValue(json, Product.class);        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(product));        assertNotNull(product.listPrice);        assertNotNull(product.variantId);        assertNotNull(product.priceText);        assertNotNull(product.name);        assertNotNull(product.description);    }    private String lowerCaseWithoutUnderScore(String key){        return key.replaceAll("_", "").toLowerCase();    }}