XSD生成的MyClass类JAXB反序列化XML片段报错求助
问题描述
我有一个通过XSD生成的类MyClass,代码如下:
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "myClass", propOrder = { "id", "code" }) public class MyClass { @XmlElement(required = true) protected String id; @XmlElement(required = true) protected String code; ... }
现在需要将一段XML字符串反序列化为MyClass对象,XML内容如下:
<id>1234dddd</id><code>ddsw</code>
使用的反序列化代码如下:
try (StringReader reader = new StringReader(xml)) { JAXBContext jaxbContext = JAXBContext.newInstance(MyClass.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); JAXBElement<MyClass> jaxbElement = (JAXBElement<MyClass>) unmarshaller.unmarshal(reader); return jaxbElement.getValue(); } catch (Exception e) { throw new RuntimeException("Ошибка десериализации", e); }
运行后出现错误:
unexpected element (uri:"", local:"id"). Expected elements are (none)
由于MyClass是自动生成的无法修改,请问如何完成XML到MyClass对象的转换?
解决方案
错误核心原因是:你的XML是无根元素的片段,而MyClass仅标注了@XmlType(定义类型结构)但没有@XmlRootElement,JAXB无法直接识别零散子元素为MyClass实例。以下是三种无需修改MyClass的可行方案:
方案1:手动为XML添加根元素
MyClass的@XmlType(name = "myClass")指定了类型名称,给XML片段包裹同名根元素后,JAXB就能匹配到对应类型:
// 给原始XML添加根元素 String wrappedXml = "<myClass>" + xml + "</myClass>"; try (StringReader reader = new StringReader(wrappedXml)) { JAXBContext jaxbContext = JAXBContext.newInstance(MyClass.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); JAXBElement<MyClass> jaxbElement = (JAXBElement<MyClass>) unmarshaller.unmarshal(reader); return jaxbElement.getValue(); } catch (Exception e) { throw new RuntimeException("Ошибка десериализации", e); }
方案2:用DOM包装XML片段(不修改原始XML)
如果不想改动原始XML内容,可通过DOM API将零散元素包装成带根节点的文档,再交给JAXB反序列化:
try { // 创建空DOM文档并添加根节点 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); Element root = doc.createElement("myClass"); doc.appendChild(root); // 解析原始XML片段,将节点导入到根节点下 Document fragmentDoc = db.parse(new InputSource(new StringReader(xml))); NodeList nodes = fragmentDoc.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = doc.importNode(nodes.item(i), true); root.appendChild(node); } // 反序列化DOM文档 JAXBContext jaxbContext = JAXBContext.newInstance(MyClass.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); JAXBElement<MyClass> jaxbElement = (JAXBElement<MyClass>) unmarshaller.unmarshal(doc); return jaxbElement.getValue(); } catch (Exception e) { throw new RuntimeException("Ошибка десериализации", e); }
方案3:自定义包装类(适用于频繁处理场景)
创建带@XmlRootElement的包装类,映射XML的零散元素,再转换为MyClass对象:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class MyClassWrapper { @XmlElement(name = "id") private String id; @XmlElement(name = "code") private String code; // 转换为MyClass的方法 public MyClass toMyClass() { MyClass myClass = new MyClass(); myClass.setId(this.id); myClass.setCode(this.code); return myClass; } // JAXB要求的无参构造器、getter/setter public MyClassWrapper() {} // 省略getter和setter }
反序列化时先得到包装类实例,再转换为目标对象:
try (StringReader reader = new StringReader(xml)) { JAXBContext jaxbContext = JAXBContext.newInstance(MyClassWrapper.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); MyClassWrapper wrapper = (MyClassWrapper) unmarshaller.unmarshal(reader); return wrapper.toMyClass(); } catch (Exception e) { throw new RuntimeException("Ошибка десериализации", e); }
内容的提问来源于stack exchange,提问作者AnnKont
相关产品推荐
相关产品推荐

