2016-02-08 75 views
2

大約有使用JAXB的馬歇爾/解組一java.util.Map前幾次的問題,其中許多得到指出回到這個例子,它的偉大工程:馬歇爾/解組嵌套地圖與JAXB

http://blog.bdoughan.com/2013/03/jaxb-and-javautilmap.html

然而,如果地圖不是@XmlRootElement的成員,我無法讓JaxB能夠編組/地圖的實例。例如,這裏有一個根元素類,

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public static class Customer { 

    private MyField myField 

    MyField getMyField() { 
     return myField 
    } 

    void setMyField(MyField myField) { 
     this.myField = myField 
    } 

} 

它的定義是外地類:

@XmlAccessorType(XmlAccessType.FIELD) 
public static class MyField{ 

    Map<String, String> getSomeMap() { 
     return someMap 
    } 

    void setSomeMap(Map<String, String> someMap) { 
     this.someMap = someMap 
    } 

    @XmlElement 
    private Map<String, String> someMap = new HashMap<String, String>() 
} 

而且一些代碼來驅動編組:

JAXBContext jc = JAXBContext.newInstance(Customer.class) 

    Customer customer = new Customer() 
    MyField myField1 = new MyField() 
    myField1.someMap.put("foo", "bar") 
    myField1.someMap.put("baz", "qux") 
    customer.myField = myField1 

    Marshaller marshaller = jc.createMarshaller() 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true) 
    marshaller.marshal(customer, System.out) 

這個例子的結果:

java.util.Map is an interface, and JAXB can't handle interfaces. 
java.util.Map does not have a no-arg default constructor. 

我正在使用Groovy而不是Java編寫我的代碼,但我認爲它不會有太大區別。

回答

0

這個問題的答案我已經結束了從Map場去除@XmlElement註釋,像這樣的具體問題:

@XmlAccessorType(XmlAccessType.FIELD) 
public static class MyField{ 

    Map<String, String> getSomeMap() { 
     return someMap 
    } 

    void setSomeMap(Map<String, String> someMap) { 
     this.someMap = someMap 
    } 

    //@XmlElement Remove this annotation 
    private Map<String, String> someMap = new HashMap<String, String>() 
} 

如果沒有這個註釋,編組/解組正常工作,並仍然將Map解釋爲XmlElement - 專門針對該註釋似乎存在錯誤。然而,正如@dlcole指出的那樣,另一種選擇(這將允許您更好地控制序列化表示的格式)是使用Jackson而不是JAXB。

0

我以前經歷過這個。底線是警告告訴你確切的問題。您已將您的字段定義爲類型java.util.Map。 JAXB不支持接口。要糾正你的問題,你需要你的領域的申報更改爲具體的地圖類型,如:

private HashMap<String, String> someMap = new HashMap<String, String>() 

您的其他選項是在你所引用的鏈接描述。您需要有一個

MapAdapter類在您提供的鏈接中引用,然後將其包含在註釋中,暗示JAXB應該如何編組/映射類型。

我覺得這個鏈接給出瞭如何建立和落實MapAdapter更清晰的例子:

JAXB: how to marshall map into <key>value</key>

+0

你錯了。如果您按照原始問題中發佈的鏈接進行操作並關注博客,您將看到「MapAdapter」僅用於更改地圖解組爲XML的方式 - 但它本來不是*僅用於實現解組/編組。您發佈的鏈接也是如此。 此外,您可以使用'java.util.List'(也是一個接口)來嘗試上面的示例,並且使用jaxb進行編組/解組沒有問題。 – Sean

+0

讓我問你這個。如果您將類型從Map更改爲HashMap,而無需其他修改,那麼它是否可以工作? – pczeus

+0

在您的回覆之後,我使用SpringBoot創建了一個測試@RestController。我能夠重現你的情況 - 列表呈現,地圖不。所以,你對Map的異常行爲是正確的。我會將我的解決方案發布到這個問題上,這對您可能無效,因爲我的解決方案是將XML呈現從JAXB更改爲傑克遜,這對我來說非常合適。 – pczeus

1

我能夠遇到使用JAXB通過創建類型@RestController的的的TestController相同的行爲,使用春季啓動。

import org.springframework.web.bind.annotation.RequestMapping 
import org.springframework.web.bind.annotation.RestController 

@RestController 
@RequestMapping(value = "test") 
class TestController { 

    @RequestMapping(value = "findList") 
    List findList() { 
     ["Test1", "Test2", "Test3"] as ArrayList<String> 
    } 

    @RequestMapping(value = "findMap") 
    Map findMap() { 
     ["T1":"Test1", "T2":"Test2", "T3":"Test3"] as HashMap<String,String> 
    } 

    @RequestMapping(value = "") 
    String find(){ 
     "Test Something" 
    } 
} 

隨着JAXB作爲SpringBoot默認實現,我可以重現該問題的/測試/ findList將正確渲染XML,但在最初的發帖描述/測試/ findMap會產生一個錯誤。

對我來說,解決這個問題的方法是將XML渲染庫切換到Jackson(還有其他一些像XStream)。

使用搖籃構建文件(的build.gradle),我只需添加傑克遜的依賴,非常相似,你會如何,如果使用Maven:

「com.fasterxml.jackson.core:jackson- core:2.7.1', 'com.fasterxml.jackson.core:jackson-annotations:2.7.1', 'com.fasterxml.jackson.core:jackson-databind:2.7.1-1', 'com .fasterxml.jackson.dataformat:jackson-dataformat-xml:2.7.1', 'org.codehaus.woodstox:woodstox-core-asl:4.4。1' ,