我们的应用程序中有一个相当常见的模式.我们在Xml中配置一个对象的集合(或列表),它们都实现了一个公共接口.在启动时,应用程序读取Xml并使用JAXB创建/配置对象列表.我从来没有想过(经过多次阅读各种帖子后)只使用JAXB的"正确方法".
例如,我们有一个接口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>
Run Code Online (Sandbox Code Playgroud)
在上面的Xml中,每个<fee>元素对应于Fee接口的具体子类.该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);
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,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);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,在上面的代码中,我们得到一个List,其中包含在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;
}
Run Code Online (Sandbox Code Playgroud)
佣金
该Fee接口的实现通常会被注释。
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class Commission implements Fee {
@XmlAttribute
private String name;
@XmlAttribute
private String rate;
}
Run Code Online (Sandbox Code Playgroud)
想要查询更多的信息
| 归档时间: |
|
| 查看次数: |
14091 次 |
| 最近记录: |