gpt4 book ai didi

java - JAXB:如何解码不同类型但具有共同父对象的对象列表?

转载 作者:搜寻专家 更新时间:2023-10-30 21:09:51 27 4
gpt4 key购买 nike

在我们的应用程序中有一个相当普遍的模式。我们在 Xml 中配置一组(或列表)对象,它们都实现一个公共(public)接口(interface)。在启动时,应用程序读取 Xml 并使用 JAXB 创建/配置对象列表。我从来没有想出(在多次阅读各种帖子之后)仅使用 JAXB 来执行此操作的“正确方法”。

例如,我们有一个接口(interface)Fee ,以及多个具体实现类,它们具有一些共同的属性,以及一些不同的属性和非常不同的行为。我们用来配置应用程序使用的费用列表的 Xml 是:

<fees>
<fee type="Commission" name="commission" rate="0.000125" />
<fee type="FINRAPerShare" name="FINRA" rate="0.000119" />
<fee type="SEC" name="SEC" rate="0.0000224" />
<fee type="Route" name="ROUTES">
<routes>
<route>
<name>NYSE</name>
<rates>
<billing code="2" rate="-.0014" normalized="A" />
<billing code="1" rate=".0029" normalized="R" />
</rates>
</route>
</routes>
...
</fee>
</fees>

在上面的Xml中,每个<fee>元素对应于 Fee 接口(interface)的具体子类。 type属性提供有关要实例化哪种类型的信息,然后在实例化后,JAXB 解码应用来自剩余 Xml 的属性。

我总是不得不求助于做这样的事情:

private void addFees(TradeFeeCalculator calculator) throws Exception {
NodeList feeElements = configDocument.getElementsByTagName("fee");
for (int i = 0; i < feeElements.getLength(); i++) {
Element feeElement = (Element) feeElements.item(i);
TradeFee fee = createFee(feeElement);
calculator.add(fee);
}
}

private TradeFee createFee(Element feeElement) {
try {
String type = feeElement.getAttribute("type");
LOG.info("createFee(): creating TradeFee for type=" + type);
Class<?> clazz = getClassFromType(type);
TradeFee fee = (TradeFee) JAXBConfigurator.createAndConfigure(clazz, feeElement);
return fee;
} catch (Exception e) {
throw new RuntimeException("Trade Fees are misconfigured, xml which caused this=" + XmlUtils.toString(feeElement), e);
}
}

在上面的代码中,JAXBConfigurator只是用于解码的 JAXB 对象的简单包装器:

public static Object createAndConfigure(Class<?> clazz, Node startNode) {
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
@SuppressWarnings("rawtypes")
JAXBElement configElement = unmarshaller.unmarshal(startNode, clazz);
return configElement.getValue();
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

最后,在上面的代码中,我们得到一个列表,其中包含在 Xml 中配置的任何类型。

有没有办法让 JAXB 自动执行此操作,而不必像上面那样编写代码来迭代元素?

最佳答案

注意:我是 EclipseLink JAXB (MOXy) JAXB (JSR-222) 的领导和成员专家组。

如果您使用 MOXy 作为 JAXB 提供者,那么您可以使用 MOXy 的 @XmlPaths 注释来扩展标准 JAXB @XmlElements 注释以执行以下操作:

费用

import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;

@XmlRootElement
public class Fees {

@XmlElements({
@XmlElement(type=Commission.class),
@XmlElement(type=FINRAPerShare.class),
@XmlElement(type=SEC.class),
@XmlElement(type=Route.class)
})
@XmlPaths({
@XmlPath("fee[@type='Commission']"),
@XmlPath("fee[@type='FINRAPerShare']"),
@XmlPath("fee[@type='SEC']"),
@XmlPath("fee[@type='Route']")
})
private List<Fee> fees;

}

佣金

Fee 接口(interface)的实现将被正常注释。

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Commission implements Fee {

@XmlAttribute
private String name;

@XmlAttribute
private String rate;

}

了解更多信息

关于java - JAXB:如何解码不同类型但具有共同父对象的对象列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15078566/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com