java - Using JAXB, how can I unmarshal an XMLelement with an attribute-defined type to an object based on that attribute?
问题描述
My application is receiving an object payload marshalled into XML, e.g:
<targetedMessage>
<sender>external application</sender>
<payload class="class.path.from.external.application.Foo">
<id>1</id>
</payload>
</targetedMessage>
The payload class (Foo in example) can be one of a number of classes with a common inheritance structure.
Each has a corresponding class in my application:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo extends Baz {
private Long id;
//other fields, getters, setters
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar extends Baz {
private Long id;
// other fields, getters, setters
}
and an enum can be used to find the local class of the object based on the foreign classpath:
public enum ForeignClass {
FOO("class.path.from.external.application.Foo", Foo.class),
BAR("class.path.from.external.application.Bar", Bar.class);
public static getClassFromForeignClassPath(String foreignClassPath) {
// return class
}
I also have a TargetedMessage
class to capture meta info regarding the message itself:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class TargetedMessage {
private String sender;
private Baz baz;
}
What annotation would be required to unmarshal the XML properly? I've tried using an XmlAdapter on the Baz
field in the TargetedMessage
class, but the ValueType parameter is always null.
@XmlAttribute
doesn't appear as though it could work either, as the value of the class
attributes are not the same as their corresponding local class names.
解决方案
你至少有两个选择。首先,您可以将“类”属性映射到字符串枚举,并在 TargetedMessage 的 #getBaz() 方法中实现实例化逻辑。XSD 如下所示(根据需要重命名类型):
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/XMLSchema" xmlns:tns="http://www.example.org/XMLSchema" elementFormDefault="qualified">
<include schemaLocation=""></include>
<simpleType name="simpleTypeClass">
<restriction base="string">
<enumeration value="class.path.from.external.application.Foo"></enumeration>
<enumeration value="class.path.from.external.application.Bar"></enumeration>
</restriction>
</simpleType>
<complexType name="payloadType">
<sequence>
<element name="id" type="string"></element>
</sequence>
<attribute name="class" type="tns:simpleTypeClass"></attribute>
</complexType>
<complexType name="targetedMessageType">
<sequence>
<element name="sender" type="string"></element>
<element name="payload" type="tns:payloadType"></element>
</sequence>
</complexType>
</schema>
其次,您可以转换您的初始 XML,以便根据其“类”属性内容重命名“有效负载”元素。例如,它可以是“payloadFoo”、“payloadBar”等。然后,您可以将其直接映射到所需的类。相应的 XSD 如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/XMLSchema" xmlns:tns="http://www.example.org/XMLSchema" elementFormDefault="qualified">
<simpleType name="simpleTypeFoo">
<restriction base="string">
<enumeration value="class.path.from.external.application.Foo"></enumeration>
</restriction>
</simpleType>
<simpleType name="simpleTypeBar">
<restriction base="string">
<enumeration value="class.path.from.external.application.Bar"></enumeration>
</restriction>
</simpleType>
<complexType name="payloadTypeFoo">
<sequence>
<element name="id" type="string"></element>
</sequence>
<attribute name="class" type="tns:simpleTypeFoo"></attribute>
</complexType>
<complexType name="payloadTypeBar">
<sequence>
<element name="id" type="string"></element>
</sequence>
<attribute name="class" type="tns:simpleTypeBar"></attribute>
</complexType>
<complexType name="payloadType">
<choice>
<element name="payloadFoo" type="tns:payloadTypeFoo" minOccurs="0" maxOccurs="1"></element>
<element name="payloadBar" type="tns:payloadTypeBar" minOccurs="0" maxOccurs="1"></element>
</choice>
</complexType>
<complexType name="targetedMessageType">
<sequence>
<element name="sender" type="string"></element>
<element name="payload" type="tns:payloadType"></element>
</sequence>
</complexType>
</schema>
推荐阅读
- if-statement - Makefie:if 语句中的目标
- flutter-layout - 应用程序上的照片大小
- sql - 如何使用 JOIN 对表使用 OFSET 和 FETCH
- asp.net-core - Visual Studio 2019 错误:启动 IISexpress 时发生错误。无法启动配置的 Visual Studio 开发 Web 服务器。拒绝访问
- automation - Ansible 在标签选项中使用变量
- r - 使用 R 函数初始化的缓存中的可用内存量:`memoise::memoise()`
- apache-kafka - 在分区上随机生成消息
- karate - 空手道:在 docker 容器中运行测试时,JS 功能不起作用
- azure - Azure Cosmos SQL 查询很慢,能否优化性能?
- ssms - 有什么方法可以取消 SSMS 中的请求?