【问题标题】:XML to Json conversion using Jackson, @JsonUnwrapped producing nulls使用 Jackson 将 XML 转换为 Json,@JsonUnwrapped 产生空值
【发布时间】:2017-02-01 14:56:07
【问题描述】:

我使用的是 java 8 和 (fasterjackson) Jackson 2.8.1。

我有一个需要使用 Java 将其转换为 json 的 xml。 xml结构是这样的:

<Input>
    <ns0:order>
        <ns0:lineItemList>
            <ns0:lineItem>
                <ns0:lineItemType>
                    <ns0:orderID>234</ns0:orderID>
                    <ns0:shipmentID>1</ns0:shipmentID>
                    <ns0:lineID>1</ns0:lineID>
                    <ns0:upc>123</ns0:upc>
                    <ns0:quantity>1</ns0:quantity>
                    <ns0:retailPrice>14</ns0:retailPrice>
                </ns0:lineItemType>
            </ns0:lineItem>
        </ns0:lineItemList>
    </ns0:order>
</Input>

我选择Jackson从xml反序列化成java,然后再从java序列化成json。目标json需要解包“lineItem”和“lineItemType”才能得到类似这样的json:

{  
  "input" : {
    "order" : {  
     "lineItemList" : [ {
        "upc" : 123,
        "quantity" : 1,
        "retailPrice" : 14,
        "orderID" : 234,
        "shipmentID" : 1,
        "lineID" : 1
      } ]
    }
  }
}

在我的 java 模型中,这里有 3 个相关的类:Order、LineItem 和 LineItemType。在订单类中,我这样注释:

@JacksonXmlProperty(localName="lineItemList")
@JsonProperty("lineItemList")
List<LineItem> lineItems;

在 LineItem 中,像这样:

@JacksonXmlProperty(localName="lineItemType")
@JsonUnwrapped
LineItemType lineItemType;

在 LineItemType 中它只是具有这种模式的属性:

...
@JacksonXmlProperty(localName="orderID")
@JsonProperty("orderID")
String orderId;

@JacksonXmlProperty(localName="lineID")
@JsonProperty("lineID")
String lineId;

...

如您所见,我尝试通过在 LineItem 类中使用 @JsonUnwrapped 来解决此问题,但最终结果是 XMLDeserializer 最终读取此注释并生成“null”值:

{  
  "input" : {
    "order" : {  
     "lineItemList" : [ {
        "upc" : null,
        "quantity" : null,
        "retailPrice" : null,
        "orderID" : null,
        "shipmentID" : null,
        "lineID" : null
      } ]
    }
  }
}

如果我省略了@JsonUnwrapped,值就会进来,但是像这样嵌套:

{  
  "input" : {
    "order" : {  
     "lineItemList" : [ {
      "lineItemType" : {
        "upc" : 123,
        "quantity" : 1,
        "retailPrice" : 14,
        "orderID" : 234,
        "shipmentID" : 1,
        "lineID" : 1
       } ]
      }
    }
  }
}

有谁知道应该如何注释才能在此处获得所需的结果(未包装但带有值)?谢谢!

【问题讨论】:

    标签: java json xml jackson


    【解决方案1】:

    您一开始就能够成功地将 XML 编组到 POJO 中吗?在您的 XML 示例中,您的第一个订单标签是自动关闭的,这可能会导致问题。

    这就是我将如何布置每个 POJO(也添加 XmlProperties)。这应该正确地从 POJO 解组为 JSON。

    顶级(Example.java):

    package com.example;
    
    import java.util.HashMap;
    import java.util.Map;
    import com.fasterxml.jackson.annotation.JsonAnyGetter;
    import com.fasterxml.jackson.annotation.JsonAnySetter;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonPropertyOrder({
        "input"
    })
    public class Example {
    
        @JsonProperty("input")
        private Input input;
        @JsonIgnore
        private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    
        /**
         * 
         * @return
         *     The input
         */
        @JsonProperty("input")
        public Input getInput() {
            return input;
        }
    
        /**
         * 
         * @param input
         *     The input
         */
        @JsonProperty("input")
        public void setInput(Input input) {
            this.input = input;
        }
    
        @JsonAnyGetter
        public Map<String, Object> getAdditionalProperties() {
            return this.additionalProperties;
        }
    
        @JsonAnySetter
        public void setAdditionalProperty(String name, Object value) {
            this.additionalProperties.put(name, value);
        }
    
    }
    

    Input.java

    package com.example;
    
    import java.util.HashMap;
    import java.util.Map;
    import com.fasterxml.jackson.annotation.JsonAnyGetter;
    import com.fasterxml.jackson.annotation.JsonAnySetter;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonPropertyOrder({
        "order"
    })
    public class Input {
    
        @JsonProperty("order")
        private Order order;
        @JsonIgnore
        private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    
        /**
         * 
         * @return
         *     The order
         */
        @JsonProperty("order")
        public Order getOrder() {
            return order;
        }
    
        /**
         * 
         * @param order
         *     The order
         */
        @JsonProperty("order")
        public void setOrder(Order order) {
            this.order = order;
        }
    
        @JsonAnyGetter
        public Map<String, Object> getAdditionalProperties() {
            return this.additionalProperties;
        }
    
        @JsonAnySetter
        public void setAdditionalProperty(String name, Object value) {
            this.additionalProperties.put(name, value);
        }
    
    }
    

    Order.java

    package com.example;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import com.fasterxml.jackson.annotation.JsonAnyGetter;
    import com.fasterxml.jackson.annotation.JsonAnySetter;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonPropertyOrder({
        "lineItemList"
    })
    public class Order {
    
        @JsonProperty("lineItemList")
        private List<LineItemList> lineItemList = new ArrayList<LineItemList>();
        @JsonIgnore
        private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    
        /**
         * 
         * @return
         *     The lineItemList
         */
        @JsonProperty("lineItemList")
        public List<LineItemList> getLineItemList() {
            return lineItemList;
        }
    
        /**
         * 
         * @param lineItemList
         *     The lineItemList
         */
        @JsonProperty("lineItemList")
        public void setLineItemList(List<LineItemList> lineItemList) {
            this.lineItemList = lineItemList;
        }
    
        @JsonAnyGetter
        public Map<String, Object> getAdditionalProperties() {
            return this.additionalProperties;
        }
    
        @JsonAnySetter
        public void setAdditionalProperty(String name, Object value) {
            this.additionalProperties.put(name, value);
        }
    
    }
    

    LineItemList.java

    package com.example;
    
    import java.util.HashMap;
    import java.util.Map;
    import com.fasterxml.jackson.annotation.JsonAnyGetter;
    import com.fasterxml.jackson.annotation.JsonAnySetter;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    @JsonPropertyOrder({
        "upc",
        "quantity",
        "retailPrice",
        "orderID",
        "shipmentID",
        "lineID"
    })
    public class LineItemList {
    
        @JsonProperty("upc")
        private Integer upc;
        @JsonProperty("quantity")
        private Integer quantity;
        @JsonProperty("retailPrice")
        private Integer retailPrice;
        @JsonProperty("orderID")
        private Integer orderID;
        @JsonProperty("shipmentID")
        private Integer shipmentID;
        @JsonProperty("lineID")
        private Integer lineID;
        @JsonIgnore
        private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    
        /**
         * 
         * @return
         *     The upc
         */
        @JsonProperty("upc")
        public Integer getUpc() {
            return upc;
        }
    
        /**
         * 
         * @param upc
         *     The upc
         */
        @JsonProperty("upc")
        public void setUpc(Integer upc) {
            this.upc = upc;
        }
    
        /**
         * 
         * @return
         *     The quantity
         */
        @JsonProperty("quantity")
        public Integer getQuantity() {
            return quantity;
        }
    
        /**
         * 
         * @param quantity
         *     The quantity
         */
        @JsonProperty("quantity")
        public void setQuantity(Integer quantity) {
            this.quantity = quantity;
        }
    
        /**
         * 
         * @return
         *     The retailPrice
         */
        @JsonProperty("retailPrice")
        public Integer getRetailPrice() {
            return retailPrice;
        }
    
        /**
         * 
         * @param retailPrice
         *     The retailPrice
         */
        @JsonProperty("retailPrice")
        public void setRetailPrice(Integer retailPrice) {
            this.retailPrice = retailPrice;
        }
    
        /**
         * 
         * @return
         *     The orderID
         */
        @JsonProperty("orderID")
        public Integer getOrderID() {
            return orderID;
        }
    
        /**
         * 
         * @param orderID
         *     The orderID
         */
        @JsonProperty("orderID")
        public void setOrderID(Integer orderID) {
            this.orderID = orderID;
        }
    
        /**
         * 
         * @return
         *     The shipmentID
         */
        @JsonProperty("shipmentID")
        public Integer getShipmentID() {
            return shipmentID;
        }
    
        /**
         * 
         * @param shipmentID
         *     The shipmentID
         */
        @JsonProperty("shipmentID")
        public void setShipmentID(Integer shipmentID) {
            this.shipmentID = shipmentID;
        }
    
        /**
         * 
         * @return
         *     The lineID
         */
        @JsonProperty("lineID")
        public Integer getLineID() {
            return lineID;
        }
    
        /**
         * 
         * @param lineID
         *     The lineID
         */
        @JsonProperty("lineID")
        public void setLineID(Integer lineID) {
            this.lineID = lineID;
        }
    
        @JsonAnyGetter
        public Map<String, Object> getAdditionalProperties() {
            return this.additionalProperties;
        }
    
        @JsonAnySetter
        public void setAdditionalProperty(String name, Object value) {
            this.additionalProperties.put(name, value);
        }
    
    }
    

    示例输出 JSON:

    {
        "input": {
            "order": {
                "lineItemList": [{
                    "upc": 123,
                    "quantity": 1,
                    "retailPrice": 14,
                    "orderID": 234,
                    "shipmentID": 1,
                    "lineID": 1
                }]
            }
        }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 试过这个,没有解决问题。当我不使用 @JsonUnwrapped 和我的 json 中不需要的层时,我仍然得到空值。不过感谢您的建议!
    • 您想要的 JSON 示例无效且不符合规范。如果您将其编辑为您想要的样子,那么我会看看是否可以进一步帮助您。这是我的代码示例输出(经过测试)的 JSON:{ "input": { "order": { "lineItemList": [{ "upc": 123, "quantity": 1, "retailPrice": 14, "orderID ": 234, "shipmentID": 1, "lineID": 1 }] } } }
    • 你的例子和我的不同之处在于你是从java开始,转成json,我从xml开始,转成java,然后用同样的模型转成json。问题就在那里。 Jackson 的 XMLMapper 实际上是在反序列化期间读取和使用 @JsonUnwrapped,这出乎我的意料,最终导致错误的原因是什么......
    【解决方案2】:

    @JsonUnwrapped 在反序列化期间被 Jackson 的 XMLMapper 读取。我以为情况并非如此,因为它说“Json”Unwr​​apped。解决方案是从我的模型中删除所有注释,并在我在 XmlModule (JacksonXmlModule) 下注册的 mixin 中应用 XML 特定注释,并在我在 JsonModule (SimpleModule) 下注册的 mixin 中应用 Json 特定注释。在从 xml 反序列化时,我使用 xmlmodule,在序列化为 json 时,我使用 jsonmodule。

    XMLMapper 使用@JsonUnwrapped 注释这一事实对我来说就像一个错误。我认为开发人员认为@JsonUnwrapped 一般适用于序列化和反序列化,但我认为这个名称意味着它应该仅限于 Json。

    【讨论】:

      猜你喜欢
      • 2017-01-22
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 2019-01-06
      • 2015-06-03
      相关资源
      最近更新 更多