英文:
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)
适配器的工作是执行从SubstitutionMap
到SubstitutionMapElement
数组的实际转换,反之亦然。
然后,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
<substituteFor>
element would look like.
Therefore I assume something like this:
<itemSubstitutionRequestDTO>
<substituteFor>
<item>
<key>x</key>
<value>23</value>
</item>
<item>
<key>y</key>
<value>3</value>
</item>
</substituteFor>
<orderId>abc</orderId>
</itemSubstitutionRequestDTO>
As the JAXB error message already told you,
it can't handle types with an interface between the < >
,
like for example your List<Map<String,Integer>>
.
However it can handle types with a normal class between < >
,
like List<SubstitutionMap>
.
So the first step is to rewrite your ItemSubstitutionRequestDTO
class
so that it does not use List<Map<String,Integer>>
, but instead List<SubstitutionMap>
.
You need to write the SubstitutionMap
class (not an interface) by yourself.
But it can be extremely simple:
public class SubstitutionMap extends HashMap<String, Integer> {
}
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 SubstitutionMapElement
s and vice versa.
Then JAXB can handle the SubstitutionMapElement
array by itself.
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) {
// ... (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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论