Java 向源自XSD的JAXB生成的类集合添加访问例程

Java 向源自XSD的JAXB生成的类集合添加访问例程,java,jaxb,adapter,delegation,facade,Java,Jaxb,Adapter,Delegation,Facade,我有一个基于XSD的嵌套XML结构。我使用JAXB进行只读解组 通常,我需要在大型结构的某处找到一个或多个元素。为了避免每次需要搜索时都遍历结构,我想添加一个带有内部缓存的优化搜索函数 定义它的最佳方式是什么?不同方式的利弊是什么 我最初考虑使用facade或adapter,adaper类在其中访问生成的类并根据需要添加方法;不过,我想征求一些建议 作为一个稍微简化的示例,需要在基于此XSD的XML中搜索具有特定boq元素的step类型的元素: <?xml version="1.0" en

我有一个基于XSD的嵌套XML结构。我使用JAXB进行只读解组

通常,我需要在大型结构的某处找到一个或多个元素。为了避免每次需要搜索时都遍历结构,我想添加一个带有内部缓存的优化搜索函数

定义它的最佳方式是什么?不同方式的利弊是什么

我最初考虑使用facade或adapter,adaper类在其中访问生成的类并根据需要添加方法;不过,我想征求一些建议

作为一个稍微简化的示例,需要在基于此XSD的XML中搜索具有特定boq元素的step类型的元素:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="test">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="group"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="group">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="step"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="step">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" ref="number"/>
        <xs:element ref="name"/>
        <xs:element ref="type"/>
        <xs:element ref="target"/>
        <xs:sequence minOccurs="0">
          <xs:element ref="boq"/>
          <xs:element ref="remote"/>
        </xs:sequence>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="number" type="xs:integer"/>
  <xs:element name="name" type="xs:NCName"/>
  <xs:element name="type" type="xs:NCName"/>
  <xs:element name="target" type="xs:NCName"/>
  <xs:element name="boq" type="xs:string"/>
  <xs:element name="remote" type="xs:string"/>
</xs:schema>
该模式是使用JAXB编译的,因此我得到了几个类。 使用解组功能,我在内存中拥有访问XML的数据结构

现在考虑一下,我需要一个优化的搜索函数,它访问定义了boq元素的所有步骤,并返回boq和remote的值(如果也定义了)

    HashMap<String,Step> resultMap = new HashMap<>();
    test.getGroup().forEach(group -> 
            group.getStep().forEach(step -> {
                    if ("searchpattern".equals(step.getBoq()))
                        resultMap.put("searchpattern", step);
            }));

封装这种搜索的最佳方法是什么?我可以编写第二个类作为包含此方法的适配器,或者有更好的选项吗?遗产使用JAXB本身的选项?使用第三方插件,如用于maven的jaxb代理插件?

有许多选项可以解决这个问题

实用类 最简单的方法是在实用程序类中简单地实现访问路由。所以,基本上您将调用SearchPatterns.offoo之类的函数,并向其传递一个模式派生类的实例。将其与foo.getSearchPatterns(其中getSearchPatterns以某种方式添加到模式派生类中)进行比较,差别并不大。好吧,好吧,不管怎么说都没那么糟糕,但是,坦率地说,谁在乎呢

使用代码注入器插件 您可以使用XJC代码注入器插件在生成的类中注入任何代码。有关示例,请参见以下问题:

如果你有问题,请问另一个问题。我意识到我们没有去XJC代码注入器的问题

这对您来说相对容易,并且允许您注入任何您想要的代码

缺点是部分Java代码将驻留在一个奇怪的XML文件中

扩展准备好的抽象类 另一种选择是使用所需的访问器方法准备一个抽象类,比如说getSearchpatterns以及它使用getGroup作为抽象方法的方法。然后让您的模式派生类扩展这个准备好的抽象类。生成的方法将实现在准备好的超类中定义的抽象方法。这本质上是一个模板方法模式

有许多方法可以使模式派生类扩展现有类。这是其中之一:

或者您也可以使用来自的继承插件。免责声明:我是作者

您可以使用模板方法+默认方法为访问器定义一个接口,并让您的模式派生类实现它,而不是扩展类

我不喜欢这个选项,因为它只是滥用继承来添加实用程序方法

编写自己的XJC插件 在要添加的访问器后面可能有一些特定的逻辑。因此,也许您不需要像使用代码注入器插件那样简单地注入代码,而是可以根据特定的逻辑实际生成访问器

然而,这是一个非常复杂的方法。有关简要概述,请参阅。如果真的有特定的逻辑,我才会接受

正式建议 我个人更喜欢将业务逻辑与模式派生类分开。我可能是那边最大的JAXB/XJC粉丝之一。我肯定会编写一个实用程序类,它提供您想要的任何访问器

我不喜欢代码注入器选项,因为这样您的部分代码就会出现在一些奇怪的XML文件中。因此,如果您要重构IDE中的任何东西,那么这些代码就不会被触及

扩展准备好的抽象类或实现准备好的接口也不是我最喜欢的。我认为这只是滥用OOP结构来添加一些实用程序代码


编写自己的插件对于没有太多XJC插件经验的开发人员来说太复杂了。此外,我无法识别可以以某种方式概括的特定逻辑,因此此选项可能根本没有意义。

请发布一个您想要生成的代码示例。有几种方法可以解决这个问题,但您只能在个案的基础上对其进行合理的评估。这足够了吗,或者我应该进一步改进它吗?请发布一个您想要生成的代码示例。如何访问定义了boq元素的所有步骤,并返回boq和remote的值,就像在Java中一样?添加了我的访问例程。为什么要在模式派生类本身中使用此访问器代码?基本上,为什么是foo.getSearchPat terns vs SearchPatterns.offoo其中SearchPatterns是一个独立的实用程序类?