马歇尔/反马歇尔地图

huangapple go评论83阅读模式
英文:

Marshall/Unmarshall Map

问题

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ItemSubstitutionRequestDTO {
    
    public ItemSubstitutionRequestDTO() {
        
    }
    
    private List<Map<String,Integer>> substituteFor = new ArrayList<Map<String,Integer>>();
    private String orderId;
    
    public List<Map<String,Integer>> getSubstituteFor() {
        return substituteFor;
    }
    
    public void setSubstituteFor(List<Map<String,Integer>> substituteFor) {
        this.substituteFor = substituteFor;
    }
    
    public String getOrderId() {
        return orderId;
    }
 
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
    
}

ERROR:

java.util.Map is an interface, and JAXB can't handle interfaces.

I can't get JaxB to be able to marshall/unmarshall instances of Map. I tried other annotations as well and found this to be one of the possible ways to solve the above error, but nothing is working.

Below is the input JSON coming from the UI side:

{ 
    "itemSubstitutionRequestDTO": { 
        "substituteFor": [{"41712": 2}],
        "orderId": "1073901"
    } 
}
英文:

> @XmlRootElement
> @XmlAccessorType(XmlAccessType.FIELD)
> public class ItemSubstitutionRequestDTO {
>
> public ItemSubstitutionRequestDTO()
> {
>
> }
>
> private List<Map<String,Integer>> substituteFor=new ArrayList<Map<String,Integer>>();
> private String orderId;
>
> public List<Map<String,Integer>> getSubstituteFor()
> {
> return substituteFor;
> }
>
> public void setSubstituteFor(List<Map<String,Integer>> substituteFor)
> {
> this.substituteFor = substituteFor;
> }
>
> public String getOrderId() {
> return orderId;
> }
>
> public void setOrderId(String orderId) {
> this.orderId = orderId;
> }
>
> }

Final result ERROR:

> java.util.Map is an interface, and JAXB can't handle interfaces.

I can't get JaxB to be able to marshall/unmarshall instances of Map.I tried other annotation also and found this is one of the possible way to solve the above error but nothing is woking.

Below is the input json which is coming from UI side

> { "itemSubstitutionRequestDTO": { "substituteFor": [{"41712":2}],
> "orderId": "1073901", } }

答案1

得分: 1

你没有说明<substituteFor>元素内部的XML内容会是什么样子。
因此,我假设内容可能类似于以下示例:

<itemSubstitutionRequestDTO>
    <substituteFor>
        <item>
            <key>x</key>
            <value>23</value>
        </item>
        <item>
            <key>y</key>
            <value>3</value>
        </item>
    </substituteFor>
    <orderId>abc</orderId>
</itemSubstitutionRequestDTO>

正如JAXB的错误消息所指示的那样,它无法处理< >之间有接口的类型,比如你的List<Map<String, Integer>>
但它可以处理< >之间有普通类的类型,比如List<SubstitutionMap>

因此,第一步是重新编写你的ItemSubstitutionRequestDTO类,以便它不再使用List<Map<String, Integer>>,而是使用List<SubstitutionMap>
你需要自己编写SubstitutionMap类(不是接口)。但它可以非常简单:

public class SubstitutionMap extends HashMap<String, Integer> {
}

现在,JAXB不会再抛出错误,但它仍然不知道如何编组/解组SubstitutionMap
因此,你需要为它编写一个XmlAdapter
我们称之为SubstitutionMapAdapter
为了让JAXB意识到这个适配器,你需要在ItemSubstitutionRequestDTO类中的substituteFor属性上加上注解:

@XmlJavaTypeAdapter(SubstitutionMapAdapter.class)

适配器的工作是执行从SubstitutionMapSubstitutionMapElement数组的实际转换,反之亦然。
然后,JAXB可以自行处理SubstitutionMapElement数组。

public class SubstitutionMapAdapter extends XmlAdapter<SubstitutionMapElement[], SubstitutionMap> {

    @Override
    public SubstitutionMap unmarshal(SubstitutionMapElement[] elements) {
        if (elements == null)
            return null;
        SubstitutionMap map = new SubstitutionMap();
        for (SubstitutionMapElement element : elements)
            map.put(element.getKey(), element.getValue());
        return map;
    }

    @Override
    public SubstitutionMapElement[] marshal(SubstitutionMap map) {
        // ...(由你自己完成)
    }
}

SubstitutionMapElement只是一个包含键和值的简单容器。

@XmlAccessorType(XmlAccessType.FIELD)
public class SubstitutionMapElement {

    private String key;
    private int value;
    
    // ... 省略构造函数、getter和setter,为了简洁起见
}
英文:

You didn't write how your XML content within the
&lt;substituteFor&gt; element would look like.
Therefore I assume something like this:

&lt;itemSubstitutionRequestDTO&gt;
    &lt;substituteFor&gt;
        &lt;item&gt;
            &lt;key&gt;x&lt;/key&gt;
            &lt;value&gt;23&lt;/value&gt;
        &lt;/item&gt;
        &lt;item&gt;
            &lt;key&gt;y&lt;/key&gt;
            &lt;value&gt;3&lt;/value&gt;
        &lt;/item&gt;
    &lt;/substituteFor&gt;
    &lt;orderId&gt;abc&lt;/orderId&gt;
&lt;/itemSubstitutionRequestDTO&gt;

As the JAXB error message already told you,
it can't handle types with an interface between the &lt; &gt;,
like for example your List&lt;Map&lt;String,Integer&gt;&gt;.
However it can handle types with a normal class between &lt; &gt;,
like List&lt;SubstitutionMap&gt;.

So the first step is to rewrite your ItemSubstitutionRequestDTO class
so that it does not use List&lt;Map&lt;String,Integer&gt;&gt;, but instead List&lt;SubstitutionMap&gt;.
You need to write the SubstitutionMap class (not an interface) by yourself.
But it can be extremely simple:

public class SubstitutionMap extends HashMap&lt;String, Integer&gt; {
}

Now JAXB doesn't throw an error anymore, but it still doesn't know how to marshal/unmarshal a SubstitutionMap.
Therefore you need to write an XmlAdapter for it.
Let's call it SubstitutionMapAdapter.
To make JAXB aware of this adapter, you need to annotate the substituteFor
property in your ItemSubstitutionRequestDTO class with:

@XmlJavaTypeAdapter(SubstitutionMapAdapter.class)

The adapter's job is to do the actual conversion from SubstitutionMap
to an array of SubstitutionMapElements and vice versa.
Then JAXB can handle the SubstitutionMapElement array by itself.

public class SubstitutionMapAdapter extends XmlAdapter&lt;SubstitutionMapElement[], SubstitutionMap&gt; {

    @Override
    public SubstitutionMap unmarshal(SubstitutionMapElement[] elements) {
        if (elements == null)
            return null;
        SubstitutionMap map = new SubstitutionMap();
        for (SubstitutionMapElement element : elements)
            map.put(element.getKey(), element.getValue());
        return map;
	}

    @Override
    public SubstitutionMapElement[] marshal(SubstitutionMap map) {
        // ... (left to you as exercise)
    }
}

The class SubstitutionMapElement is just a simple container for a key and a value.

@XmlAccessorType(XmlAccessType.FIELD)
public class SubstitutionMapElement {

    private String key;
    private int value;
	
	// ... constructors, getters, setters omitted here for brevity
}

huangapple
  • 本文由 发表于 2020年8月29日 23:48:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63648899.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定