使用Jackson进行反序列化时,如何放松命名策略



我一直在尝试升级JSON模块,以使用Jackson的FasterXML(2.6.3)版本,而不是旧的Codehaus模块。在升级过程中,我注意到使用FasterXML而不是Codehaus时,命名策略有所不同。

Codehaus在命名策略方面更为灵活。下面的测试强调了我在使用FasterXML时面临的问题。如何配置ObjectMapper,使其遵循与Codehaus相同的策略?

我无法更改JSONProperty注释,因为有数百个注释。我希望升级在命名策略方面向后兼容。

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
/*import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.PropertyNamingStrategy;*/
import org.junit.Assert;
import org.junit.Test;
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);
        Product product = mapper.readValue(VALID_PRODUCT_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);
    }
}

@JsonProperty会覆盖自2.4.0版本以来fasterxml中的任何PropertyNamingStrategy。然而,尚未发布的2.7.0版本将提供一个功能,允许您选择回到旧的行为。还有一个未实现的建议是在每个注释级别切换,但这对您没有真正的帮助。

在映射时,Codehaus似乎确实在@JsonProperty值之上应用了PropertyNamingStrategy,尽管我找不到任何明确的文档。这似乎也是fasterxml 2.4.0之前的行为。下面是另一个有人注意到相同行为差异的例子。

虽然SkinnyJ提供的解决方案非常适合您的问题,但如果您不能等到2.7发布,您可以应用以下破解方法来解决问题。

其想法是转换传入的JSON以匹配bean定义中的属性。下面的代码可以做到这一点。应注意以下几点:

  1. 如果您正在处理嵌套结构,则必须实现递归函数才能实现此转换
  2. 进行转换时会有一些开销

代码:

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();
    }
}

相关内容

  • 没有找到相关文章

最新更新