문제

I'm trying to use MOXy JAXB to unmarshal some JSON/XML in an Apache CFX project. The following request gives me trouble:

{"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"]}
}

Here, AppData is unmarshalled as a List<AppDatum>, however the list only contains the last element. Notably, the "MetaDataTags" element is correctly unmarshalled as a List<String> of size 3.

Surprisingly, the following request can be submitted with the same result, despite the fact the "AppData" should expect a List<AppDatum> (I can't help but feel this is related):

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

This XML equivalent (or what I see to be the XML equivalent) is parsed as expected:

<?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>

The JAXB class in question (generated by XJC, comments elided):

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

and my 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>

Any idea what could be causing this issue? Is this a bug in the 2.5.1 Release of MOXy? Or is there a "switch" somewhere that I need to set?

도움이 되었습니까?

해결책

Based on your mapping, the folloiwng would be the expected JSON document:

{
   "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"
   }
}

The following is the standalone example I wrote based on yours to read in the XML and output the corresponding 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);
    }

}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top