JAXB Unmarsharrller:映射了 XMLAttributes,但未映射其 XmlElements
JAXB Unmarsharller: XMLAttributes are mapped, but its XmlElements are not
TL;DR: 当我从 XML 解组到 POJO 时,我只有很好映射的 XmlAttributes,但是所有 XmlElement 都是空的。
你好!
我有以下问题。此 class 是使用 JAXB
生成的
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"activity"
})
@XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
@XmlElement(required = true)
protected Activity activity;
@XmlAttribute(name = "schemaVersion", required = true)
protected float schemaVersion;
@XmlAttribute(name = "actionType")
protected ActionTypes actionType;
@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar timestamp;
这是一个例子XML
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
但是,当这段代码被执行时(请不要评判我,这是遗留代码):
Object xmlClass = Class.forName("com.lorem.ipsum." + className).getConstructor().newInstance();
final JAXBContext jaxbContext = JAXBContext.newInstance(xmlClass.getClass());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(element));
结果“对象”的所有 XmlAttribute 都映射良好,但没有一个 XmlElement
PS:生成的 class 中的名称空间是手动添加的,如果我不这样做,我会出现以下异常:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://lorem.ipsum.com/", local:"activityDetails"). Expected elements are <{}activityDetails>
提前致谢。
更新: 如果我设置所有 @XmlElement
命名空间 属性 我最终映射元素,但我必须干预所有 class es。有没有另一种方法可以实现这一点而不必修改所有 classes 的所有字段?
我想我能弄清楚问题所在。发生这种情况是因为您没有为 XML 中的命名空间提供任何前缀。以下代码适用于您提供的示例 XML:
XML:
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns:ns0="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
ActivityDetails.class:
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
private Activity activity;
@XmlAttribute
private float schemaVersion;
@XmlAttribute
private String actionType;
@XmlAttribute
private String timestamp;
}
Activity.class:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Activity {
private ActivityID activityId;
}
ActivityID.class:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class ActivityID {
private String start;
private String end;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("activity.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(ActivityDetails.class).createUnmarshaller();
final ActivityDetails activityDetails = unmarshaller.unmarshal(xmlStreamReader, ActivityDetails.class).getValue();
System.out.println(activityDetails.toString());
Marshaller marshaller = JAXBContext.newInstance(ActivityDetails.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(activityDetails, System.out);
}
}
以下是您的输出:
ActivityDetails(activity=Activity(activityId=ActivityID(start=2020-01-01T03:00:00Z, end=2020-01-02T02:59:00Z)), schemaVersion=2.0, actionType=CREATE, timestamp=2020-01-02T15:31:50.549Z)
<ns0:activityDetails xmlns:ns0="http://lorem.ipsum.com/" schemaVersion="2.0" actionType="CREATE" timestamp="2020-01-02T15:31:50.549Z">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</ns0:activityDetails>
最后我找到了这个解决方案:我没有将命名空间放在每个 XMLElements 中,而是将以下 package-info.java
放在生成的 类.
包中
@XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
namespace="http://lorem.ipsum.com/",
xmlns={@XmlNs(prefix="", namespaceURI="http://lorem.ipsum.com/")})
package com.lorem.ipsum.generated;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
TL;DR: 当我从 XML 解组到 POJO 时,我只有很好映射的 XmlAttributes,但是所有 XmlElement 都是空的。
你好!
我有以下问题。此 class 是使用 JAXB
生成的@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"activity"
})
@XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
@XmlElement(required = true)
protected Activity activity;
@XmlAttribute(name = "schemaVersion", required = true)
protected float schemaVersion;
@XmlAttribute(name = "actionType")
protected ActionTypes actionType;
@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar timestamp;
这是一个例子XML
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
但是,当这段代码被执行时(请不要评判我,这是遗留代码):
Object xmlClass = Class.forName("com.lorem.ipsum." + className).getConstructor().newInstance();
final JAXBContext jaxbContext = JAXBContext.newInstance(xmlClass.getClass());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(element));
结果“对象”的所有 XmlAttribute 都映射良好,但没有一个 XmlElement
PS:生成的 class 中的名称空间是手动添加的,如果我不这样做,我会出现以下异常:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://lorem.ipsum.com/", local:"activityDetails"). Expected elements are <{}activityDetails>
提前致谢。
更新: 如果我设置所有 @XmlElement
命名空间 属性 我最终映射元素,但我必须干预所有 class es。有没有另一种方法可以实现这一点而不必修改所有 classes 的所有字段?
我想我能弄清楚问题所在。发生这种情况是因为您没有为 XML 中的命名空间提供任何前缀。以下代码适用于您提供的示例 XML:
XML:
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns:ns0="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
ActivityDetails.class:
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
private Activity activity;
@XmlAttribute
private float schemaVersion;
@XmlAttribute
private String actionType;
@XmlAttribute
private String timestamp;
}
Activity.class:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Activity {
private ActivityID activityId;
}
ActivityID.class:
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class ActivityID {
private String start;
private String end;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("activity.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(ActivityDetails.class).createUnmarshaller();
final ActivityDetails activityDetails = unmarshaller.unmarshal(xmlStreamReader, ActivityDetails.class).getValue();
System.out.println(activityDetails.toString());
Marshaller marshaller = JAXBContext.newInstance(ActivityDetails.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(activityDetails, System.out);
}
}
以下是您的输出:
ActivityDetails(activity=Activity(activityId=ActivityID(start=2020-01-01T03:00:00Z, end=2020-01-02T02:59:00Z)), schemaVersion=2.0, actionType=CREATE, timestamp=2020-01-02T15:31:50.549Z)
<ns0:activityDetails xmlns:ns0="http://lorem.ipsum.com/" schemaVersion="2.0" actionType="CREATE" timestamp="2020-01-02T15:31:50.549Z">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</ns0:activityDetails>
最后我找到了这个解决方案:我没有将命名空间放在每个 XMLElements 中,而是将以下 package-info.java
放在生成的 类.
@XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
namespace="http://lorem.ipsum.com/",
xmlns={@XmlNs(prefix="", namespaceURI="http://lorem.ipsum.com/")})
package com.lorem.ipsum.generated;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;