如何使用MOXy将json解组为java.util.Map <string,object =“”>?</string,>

时间:2014-11-26 01:27:47

标签: java json jaxb moxy

我知道有类似的问题,例如How to marshal/unmarshal a Map<Integer, List<Integer>>?JAXB java.util.Map binding。我也经常阅读Blaise Doughan的博客,特别是这篇文章:http://blog.bdoughan.com/2013/03/jaxb-and-javautilmap.html并试图尽可能地遵循他的建议,但是我仍然无法成功解组json有效载荷并非常感谢你的帮助。 / p>

unmarshal的json有效负载如下所示:

{
    "uri":"\\foo\\dosomthing",
    "action":"POST",
    "queryParameters":[
        "$filter=aaa",
        "$orderby=bbb"
    ],
    "requestData":{
        "data1":{
            "key1":"value1",
            "key2":"value2"
        },
        "ids":[
            "1234",
            "0294"
        ]
    }
}

我有问题解决&#34;数据&#34;进入java.util.Map。 &#34;数据&#34;字段没有特定的架构,因此它可以包含数组,键值对或任何其他有效的json数据。我决定使用Map来包装它。根据我研究的内容,我认为我需要XmlAdapter才能正确转换数据。

以下是我的代码:

Java架构类

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class CustomerRequest
{
    public CustomerRequest() {}

    public CustomerRequest(String uri, String action, List<String>
 queryParameters, Map<String, Object> reqeustData)
    {
        this.uri = uri;
        this.action = action;
        this.queryParameters = queryParameters;
        this.requestData = reqeustData;
    }

    public String getUri()
    {
        return uri;
    }

    public String getAction()
    {
        return action;
    }

    public List<String> getQueryParameters()
    {
        return Collections.unmodifiableList(queryParameters);
    }

    public Map<String, Object> getRequestData()
    {
        return Collections.unmodifiableMap(requestData);
    }

    @XmlElement
    private String uri;

    @XmlElement
    private String action;

    @XmlElementWrapper
    private List<String> queryParameters = new ArrayList<String>();

    @XmlPath(".")
    @XmlJavaTypeAdapter(StringObjectMapAdapter.class)
    private Map<String, Object> requestData = new HashMap<String, Object>();

}

XmlAdpater:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.eclipse.persistence.oxm.annotations.XmlVariableNode;

public class StringObjectMapAdapter extends 
XmlAdapter<StringObjectMapAdapter.AdaptedMap, Map<String, Object>> 
{

public static class AdaptedEntry
{
    @XmlTransient
    public String key;

    @XmlValue
    public Object value = new Object();
}
public static class AdaptedMap
{
    @XmlVariableNode("key")
    List<AdaptedEntry> entries = new ArrayList<AdaptedEntry>();
}

@Override
public AdaptedMap marshal(Map<String, Object> map) throws Exception 
{
    AdaptedMap adaptedMap = new AdaptedMap();

    for (Entry<String, Object> entry : map.entrySet())
    {
        AdaptedEntry adaptedEntry = new AdaptedEntry();
        adaptedEntry.key = entry.getKey();
        adaptedEntry.value = entry.getValue();
        adaptedMap.entries.add(adaptedEntry);
    }
    return adaptedMap;
}

@Override
public Map<String, Object> unmarshal(AdaptedMap adaptedMap) throws Exception 
{
    List<AdaptedEntry> adapatedEntries = adaptedMap.entries;
    Map<String, Object> map = new HashMap<String, Object>(adapatedEntries.size());

    for (AdaptedEntry adaptedEntry : adapatedEntries )
    {
        map.put(adaptedEntry.key, adaptedEntry.value);
    }

    return map;
}

}

最后是我的测试应用

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.testng.annotations.Test;

public class TestStringObjectMapAdapter {

    @Test
    public void testUnmarshalFromJson() throws Exception 
    {
        JAXBContext jc = JAXBContext.newInstance(CustomerRequest.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        unmarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
        StreamSource json = new StreamSource("test-data.json");
        CustomerRequest request= unmarshaller.unmarshal(json,   
            CustomerRequest.class).getValue();

        assert(request.getUri().equals("\\foo\\dosomthing"));
        assert(request.getAction().equals("POST"));
    }
}

然后,当测试应用程序运行时,会生成java.lang.ClassCastException异常:

FAILED: testUnmarshalFromJson
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DocumentImpl cannot be cast to org.w3c.dom.Element
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.endSelfNodeValue(XMLCompositeObjectMappingNodeValue.java:468)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endDocument(UnmarshalRecordImpl.java:606)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endElement(UnmarshalRecordImpl.java:1084)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:304)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:179)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:125)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:140)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:857)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:707)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:655)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:301)
    at com.absolute.asb.urp.services.domain.TestStringObjectMapAdapter.testUnmarshalFromJson(TestStringObjectMapAdapter.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

1 个答案:

答案 0 :(得分:1)

也许您应该尝试创建正确的MoXY JAXBContext,如:

    private static synchronized JAXBContext createJAXBContext() throws JAXBException {
        if(jc == null){
            jc = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[] {CustomerReqeust.class}, null);
        }
        return jc;
    }

或使用http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

中提到的其他方式

Btw&#34; CustomerReqeust&#34;拼写有点错误: - )