JAXB:如何解组不同类型但具有公共父对象的List?

发布于 2021-01-30 17:36:57

在我们的应用程序中有一个相当普遍的模式。我们在Xml中配置一组配置对象(或列表)的对象,它们全部实现一个公共接口。在启动时,应用程序读取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接口的具体子类。该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自动执行此操作而不必编写代码来迭代上述元素?

关注者
0
被浏览
63
1 个回答
推荐阅读
知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看