使用MOXy JAXB 2.5.1解组复杂JSON对象的数组

时间:2013-11-18 19:51:58

标签: json jaxb moxy

我正在尝试使用MOXy JAXB在Apache CFX项目中解组一些JSON / XML。以下请求给我带来了麻烦:

{"CC.ConsumerPersistAppDataRequest" : {
    "SessionId" : "42",
    "AppData" : [
    {"AppDatum" : {
        "TimeStamp" : 1384548486,
        "Value" : "Some kind of String would go here"}},
    {"AppDatum" : {
        "TimeStamp" : 1384548578,
        "Value" : "I hope I am understanding this format correctly!"}},
    {"AppDatum" : {
        "TimeStamp" : 1384549696,
        "Value" : "One more time for the road..."}}],
    "MetaDataTags" : ["dumb", "dummy", "data"]}
}

此处,AppData作为List< AppDatum>进行解组,但该列表仅包含最后一个元素。值得注意的是,“MetaDataTags”元素被正确地解组为List< String>大小为3。

令人惊讶的是,尽管“AppData”应该期望List< AppDatum>,但是可以提交具有相同结果的以下请求。 (我不禁觉得这是相关的):

{"CC.ConsumerPersistAppDataRequest" : {
    "SessionId" : "42",
    "AppData" : {
        "AppDatum" : {
            "TimeStamp" : 1384548486,
            "Value" : "Some kind of String would go here"
        }
    }
}}

这个XML等价物(或我看到的XML等价物)按预期解析:

<?xml version="1.0" encoding="UTF-8"?>
<cc:ConsumerPersistAppDataRequest xmlns:cc="http://org/alg/ari/pnd/introspect/webservices/consumercomms">
   <SessionId>42</SessionId>
   <AppData>
      <AppDatum>
         <TimeStamp>1384548486</TimeStamp>
         <Value>Some kind of String would go here</Value>
      </AppDatum>
      <AppDatum>
        <TimeStamp>1384548578</TimeStamp>
        <Value>I hope I am understanding this format correctly!</Value>
      </AppDatum>
      <AppDatum>
        <TimeStamp>1384549696</TimeStamp>
        <Value>One more time for the road...</Value>
      </AppDatum>
   </AppData>
   <MetaDataTags>dumb dummy data</MetaDataTags>
</cc:ConsumerPersistAppDataRequest>

有问题的JAXB类(由XJC生成,评论已被删除):

package org.alg.ari.pnd.introspect.webservices.consumercomms;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlList;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "sessionId",
    "appData",
    "metaDataTags"
})
@XmlRootElement(name = "ConsumerPersistAppDataRequest")
public class ConsumerPersistAppDataRequest {

    @XmlElement(name = "SessionId", required = true)
    protected String sessionId;
    @XmlElement(name = "AppData", required = true)
    protected ConsumerPersistAppDataRequest.AppData appData;
    @XmlList
    @XmlElement(name = "MetaDataTags", required = true)
    protected List<String> metaDataTags;

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String value) {
        this.sessionId = value;
    }

    public ConsumerPersistAppDataRequest.AppData getAppData() {
        return appData;
    }

    public void setAppData(ConsumerPersistAppDataRequest.AppData value) {
        this.appData = value;
    }

    public List<String> getMetaDataTags() {
        if (metaDataTags == null) {
            metaDataTags = new ArrayList<String>();
        }
        return this.metaDataTags;
    }


    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "appDatum"
    })
    public static class AppData {

        @XmlElement(name = "AppDatum", required = true)
        protected List<ConsumerPersistAppDataRequest.AppData.AppDatum> appDatum;

        public List<ConsumerPersistAppDataRequest.AppData.AppDatum> getAppDatum() {
            if (appDatum == null) {
                appDatum = new ArrayList<ConsumerPersistAppDataRequest.AppData.AppDatum>();
            }
            return this.appDatum;
        }


        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
            "timeStamp",
            "value"
        })
        public static class AppDatum {

            @XmlElement(name = "TimeStamp")
            protected long timeStamp;
            @XmlElement(name = "Value", required = true)
            protected String value;

            public long getTimeStamp() {
                return timeStamp;
            }

            public void setTimeStamp(long value) {
                this.timeStamp = value;
            }

            public String getValue() {
                return value;
            }

            public void setValue(String value) {
                this.value = value;
            }
        }
    }
}

和我的MoxyJsonProvider bean

  <bean id="moxy-json-provider"
    class="org.eclipse.persistence.jaxb.rs.MOXyJsonProvider">
    <property name="attributePrefix" value="@" />
    <property name="formattedOutput" value="true" /> <!-- set to false for production! -->
    <property name="includeRoot" value="true" />
    <property name="marshalEmptyCollections" value="false" />
    <property name="valueWrapper" value="$" />
    <property name="namespacePrefixMapper" ref="json-ns-mapper" />
  </bean>

知道可能导致此问题的原因是什么?这是MOXy 2.5.1版本中的错误吗?或者我需要设置一个“开关”吗?

1 个答案:

答案 0 :(得分:0)

根据您的映射,下面的内容将是预期的JSON文档:

{
   "CC.ConsumerPersistAppDataRequest" : {
      "SessionId" : "42",
      "AppData" : {
         "AppDatum" : [ {
            "TimeStamp" : 1384548486,
            "Value" : "Some kind of String would go here"
         }, {
            "TimeStamp" : 1384548578,
            "Value" : "I hope I am understanding this format correctly!"
         }, {
            "TimeStamp" : 1384549696,
            "Value" : "One more time for the road..."
         } ]
      },
      "MetaDataTags" : "dumb dummy data"
   }
}

以下是我根据您的内容编写的独立示例,以读取XML并输出相应的JSON:

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(ConsumerPersistAppDataRequest.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum20056524/input.xml");
        ConsumerPersistAppDataRequest result = (ConsumerPersistAppDataRequest) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        marshaller.setProperty(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@");
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
        marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
        marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, "$");
        Map<String, String> jsonNsMapper = new HashMap<String, String>(1);
        jsonNsMapper.put("http://org/alg/ari/pnd/introspect/webservices/consumercomms", "CC");
        marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, jsonNsMapper);
        marshaller.marshal(result, System.out);
    }

}