简体   繁体   English

JAXB无法封送类型“ java.util.HashMap”

[英]JAXB unable to marshal type “java.util.HashMap”

I have a map with string as an key and an interface as an value. 我有一个以字符串为键和接口为值的映射。 I have written a adapter to handle interface and provided an annotation @XmlAnyElement to the map field. 我已经编写了一个适配器来处理接口,并为map字段提供了注释@XmlAnyElement。 Now I am getting error saying "unable to marshal type "java.util.HashMap" as an element because it is missing an @XmlRootElement annotation". 现在,我收到错误消息,说“无法将类型“ java.util.HashMap”作为元素编组,因为它缺少@XmlRootElement注释。 Can anyone help me in this matter? 谁能在这件事上帮助我?

This error is due Map has not a XmlRootElement. 此错误是由于Map没有XmlRootElement。 Let's see an example: 让我们来看一个例子:

This is the interface: 这是接口:

public interface IEmployee {

    String getFirstName();

    void setFirstName(final String firstName);

    String getLastName();

    void setLastName(final String lastName);

}

And this, the concrete implementation: 这是具体的实现:

@XmlRootElement(name = "employee")
public class Employee implements IEmployee {

    private String firstName;
    private String lastName;

    // getters and setters

}

JAXB object with map: 带有地图的JAXB对象:

import java.util.Map;

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

@XmlRootElement(name = "employees")
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeMap {

    @XmlJavaTypeAdapter(EmployeeMapAdapter.class)
    private Map<String, IEmployee> map;

    // getter and setter

}

We need create an adapter to handle the map in EmployeeMap with a list simulating the map. 我们需要创建一个适配器来处理EmployeeMap的地图,并带有一个模拟地图的列表。 Look like this: 看起来像这样:

public class EmployeeMapAdapter extends XmlAdapter<EmployeeMapAdapter.AdaptedMap, Map<String, Employee>> {

    public static class AdaptedMap {

        public List<Entry> entry = new ArrayList<>();

        public static class Entry {

            public String key;
            public Employee value;

        }

    }

    @Override
    public AdaptedMap marshal(final Map<String, Employee> map) throws Exception {
        final AdaptedMap adaptedMap = new AdaptedMap();
        for (final Map.Entry<String, Employee> mapEntry : map.entrySet()) {
            final Entry entry = new Entry();
            entry.key = mapEntry.getKey();
            entry.value = mapEntry.getValue();
            adaptedMap.entry.add(entry);
        }
        return adaptedMap;
    }

    @Override
    public Map<String, Employee> unmarshal(final AdaptedMap adaptedMap) throws Exception {
        final Map<String, Employee> map = new HashMap<>();
        for (final Entry entry : adaptedMap.entry) {
            map.put(entry.key, entry.value);
        }
        return map;
    }

}

Due the JAXB does not handle interfaces, only value classes and content interfaces, the adapter must use the concrete implementation. 由于JAXB不处理接口,仅处理值类和内容接口,因此适配器必须使用具体的实现。

Marshalling example: 编组示例:

final Map<String, IEmployee> map = new HashMap<>();

final Employee emp1 = new Employee();
emp1.setFirstName("Bruno");
emp1.setLastName("César");
map.put("1", emp1);

final Employee emp2 = new Employee();
emp2.setFirstName("Ribeiro");
emp2.setLastName("Silva");
map.put("2", emp2);

final EmployeeMap employeeMap = new EmployeeMap();
employeeMap.setMap(map);

final JAXBContext jaxbContext = JAXBContext.newInstance(EmployeeMap.class);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

final File file = new File("D:/Temp/employees.xml");
if (!file.exists()) {
    file.mkdirs();
}

jaxbMarshaller.marshal(employeeMap, file);

Results in: 结果是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
    <map>
        <entry>
            <key>2</key>
            <value>
                <firstName>Ribeiro</firstName>
                <lastName>Silva</lastName>
            </value>
        </entry>
        <entry>
            <key>1</key>
            <value>
                <firstName>Bruno</firstName>
                <lastName>César</lastName>
            </value>
        </entry>
    </map>
</employees>

And unmarshalling: 并解组:

final JAXBContext jaxbContext = JAXBContext.newInstance(EmployeeMap.class);
final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
final EmployeeMap empMap = (EmployeeMap) jaxbUnmarshaller.unmarshal(new File("D:/temp/employees.xml"));

for (final String id : empMap.getMap().keySet()) {
    System.out.println(empMap.getMap().get(id).getFirstName());
    System.out.println(empMap.getMap().get(id).getLastName());
}

Results in: 结果是:

Ribeiro
Silva
Bruno
César

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM