如何通过XSD定义生成包含HashMap的Java Employee类?
问题描述
我们的应用需要用XML Schema定义(XSD)生成Java类,其中要求用HashMap存储键值对。期望生成的Employee类如下:
public class Employee{ private String name; private Map<String, Object> dataMap; }
我试过schemagen、JAXBContext等工具,但都没成功。自己编写了下面的XSD定义,不过生成的Java类里dataMap是List类型而非Map,当前使用JDK 1.8,恳请提供解决办法或建议:
<xs:complexType name="employee"> <xs:sequence> <xs:element name="dataMap"> <xs:complexType> <xs:sequence> <xs:element name="entry" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="key" minOccurs="0" type="xs:string"/> <xs:element name="value" minOccurs="0" type="xs:anyType"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="value" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType>
解决方案
JAXB默认不会自动将这种嵌套entry的结构转换成Map,需要通过自定义绑定或适配器来实现,以下是两种可行方法:
方法1:使用JAXB绑定文件(推荐)
创建一个bindings.xjb绑定文件,指定将entry集合转换为Map类型:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" jaxb:version="2.1"> <jaxb:bindings schemaLocation="你的XSD文件名.xsd"> <!-- 绑定employee类型下的entry元素 --> <jaxb:bindings node="//xs:complexType[@name='employee']//xs:element[@name='dataMap']//xs:complexType//xs:sequence//xs:element[@name='entry']"> <jaxb:property> <jaxb:baseType name="java.util.Map<String, Object>"/> <jaxb:key node="./xs:complexType/xs:sequence/xs:element[@name='key']"/> <jaxb:value node="./xs:complexType/xs:sequence/xs:element[@name='value']"/> </jaxb:property> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
执行xjc命令生成Java类时指定该绑定文件:
xjc -b bindings.xjb 你的XSD文件名.xsd
方法2:手动添加XML适配器
如果已经生成了Java类,可以通过自定义适配器将List
- 编写适配器类:
public class EntryListToMapAdapter extends XmlAdapter<List<Entry>, Map<String, Object>> { @Override public Map<String, Object> unmarshal(List<Entry> entries) throws Exception { Map<String, Object> map = new HashMap<>(); if (entries != null) { for (Entry entry : entries) { if (entry.getKey() != null) { map.put(entry.getKey(), entry.getValue()); } } } return map; } @Override public List<Entry> marshal(Map<String, Object> map) throws Exception { List<Entry> entries = new ArrayList<>(); if (map != null) { for (Map.Entry<String, Object> entry : map.entrySet()) { Entry e = new Entry(); e.setKey(entry.getKey()); e.setValue(entry.getValue()); entries.add(e); } } return entries; } }
- 修改生成的Employee类,给
dataMap字段添加适配器注解:
public class Employee{ private String name; @XmlJavaTypeAdapter(EntryListToMapAdapter.class) private Map<String, Object> dataMap; // 此处补充getter、setter方法 }
额外修正
你的XSD中定义的是<xs:element name="value" type="xs:string" minOccurs="0"/>,但期望的Employee类是name字段,记得把XSD里的这个元素名称改成name,否则生成的类里会是value字段而非name。
内容的提问来源于stack exchange,提问作者Arpit S
相关产品推荐
相关产品推荐

