如何使用泛型对XML元素列表进行反序列化?
如何用泛型反序列化XML元素列表?
我尝试用泛型方法反序列化XML中的元素列表,但代码运行失败,相关代码和错误信息如下:
XML内容:
String xml = "<cats><cat><name>Ms. Piggy</name><city>Londen</city></cat><cat><name>Ms. Jerry</name><city>Londen</city></cat></cats>"; Processor pr = new Processor(); List<CatXML> cats = pr.xmlToObjectList(xml, CatXML.class);
Processor类代码:
public class Processor { public <T> List<T> xmlToObjectList(String xmlContainsObject, Class<T> objectType) { try { JAXBContext context = JAXBContext.newInstance(objectType); Unmarshaller unmarshaller = context.createUnmarshaller(); StringReader reader = new StringReader(xmlContainsObject); return (List<T>) unmarshaller.unmarshal(reader); } catch (Exception e) { throw new RuntimeException(e); } } }
CatXML类代码:
@XmlRootElement(name = "cat") @XmlAccessorType(XmlAccessType.FIELD) public class CatXML implements Serializable { private String name = ""; private String city = ""; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
运行后抛出错误:
Exception in thread "main" java.lang.RuntimeException: jakarta.xml.bind.UnmarshalException: unexpected element (uri:"", local:"cats"). Expected elements are <{}cat> at org.example.Processor.xmlToObjectList(Processor.java:90) at org.example.Main.main(Main.java:36) Caused by: jakarta.xml.bind.UnmarshalException: unexpected element (uri:"", local:"cats"). Expected elements are <{}cat> at org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:701)
解决方案
错误原因
你的XML根元素是<cats>,但JAXB上下文只注册了CatXML类(对应<cat>元素),反序列化时JAXB找不到匹配<cats>的类,因此抛出异常。JAXB无法直接将根元素为集合容器的XML反序列化为List,需要一个包装类来对应根元素。
方法一:创建根元素包装类
- 新增
CatsXML类,对应<cats>根元素,内部包含List<CatXML>:
@XmlRootElement(name = "cats") @XmlAccessorType(XmlAccessType.FIELD) public class CatsXML implements Serializable { @XmlElement(name = "cat") private List<CatXML> cats; public List<CatXML> getCats() { return cats; } public void setCats(List<CatXML> cats) { this.cats = cats; } }
- 修改调用逻辑,先反序列化为
CatsXML,再取出列表:
Processor pr = new Processor(); CatsXML catsWrapper = pr.xmlToObject(xml, CatsXML.class); List<CatXML> cats = catsWrapper.getCats();
同时可以修改Processor类,添加通用的单对象反序列化方法:
public class Processor { public <T> T xmlToObject(String xml, Class<T> objectType) { try { JAXBContext context = JAXBContext.newInstance(objectType); Unmarshaller unmarshaller = context.createUnmarshaller(); StringReader reader = new StringReader(xml); return objectType.cast(unmarshaller.unmarshal(reader)); } catch (Exception e) { throw new RuntimeException(e); } } }
方法二:不创建包装类,直接处理XML流
如果不想新增包装类,可以用XMLStreamReader定位到<cat>元素,逐个反序列化:
public <T> List<T> xmlToObjectList(String xml, Class<T> objectType) { try { JAXBContext context = JAXBContext.newInstance(objectType); Unmarshaller unmarshaller = context.createUnmarshaller(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xml)); // 跳过根元素<cats>,定位到<cat>元素 while (reader.hasNext()) { if (reader.isStartElement() && reader.getLocalName().equals(objectType.getAnnotation(XmlRootElement.class).name())) { break; } reader.next(); } List<T> result = new ArrayList<>(); while (reader.isStartElement() && reader.getLocalName().equals(objectType.getAnnotation(XmlRootElement.class).name())) { T obj = unmarshaller.unmarshal(reader, objectType).getValue(); result.add(obj); // 移动到下一个元素 reader.next(); } return result; } catch (Exception e) { throw new RuntimeException(e); } }
这种方法不需要修改现有类,直接通过XML流遍历目标元素完成反序列化。
内容的提问来源于stack exchange,提问作者user10053673
相关产品推荐
相关产品推荐

