簡體   English   中英

從生成的jaxb類中的抽象Java類實現抽象方法(繼承)

[英]Implementing abstract methods from abstract java class in generated jaxb class (inheritance)

問題:

我有一個稱為Schema的基類,它是抽象的,它是一個非生成的類。 我有兩個從Schema繼承的生成的JAXB類:FixedWidthSchema和DelimitedSchema。

我使用外部綁定(xjb)文件來指定XSD和Java類之間的映射。

在基類Schema中,我定義了一些方法:

  1. public Sc​​hema static create(Model m),它從提供的Model創建一個Schema。
  2. 公共抽象 Writer marshal(),它將當前的Schema對象(FixedWidth或Delimited)編組為Writer輸出。
  3. public Sc​​hema unmarshal(Reader r),它將已提供的Reader輸入解組到Schema對象(input = XML文件)。
  4. 公共抽象 void validate(),用於驗證創建的模式。
  5. 公共抽象布爾值isFixedWidth(),它指示創建的模式是否為固定寬度模式。
  6. public abstract boolean isDelimited(),它指示創建的模式是否是帶分隔符的模式。

我希望在生成的jaxb類FixedWidthSchema和DelimitedSchema中實現抽象方法(2、4、5和6)。 兩者都擴展了基類Schema。 因此,當我調用Schema.isFixedWidth()時,基礎繼承的類將應答此調用並告訴調用者:true / false。 只有派生類知道他們是誰:fixedwidth或delimited。

這是XSD:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="schema" type="SchemaType"/>
   <xs:complexType name="SchemaType">
      <xs:choice>
         <xs:element minOccurs="1" maxOccurs="1" name="delimited" type="DelimitedSchemaType"/>
         <xs:element minOccurs="1" maxOccurs="1" name="fixedwidth" type="FixedWidthSchemaType"/>
      </xs:choice>
</xs:complexType>
<xs:complexType name="DelimitedSchemaType">
    <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="locale" type="LocaleType"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="FixedWidthSchemaType">
    <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="locale" type="LocaleType"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="LocaleType">
    <xs:attribute name="language" type="languageType" use="required"/>
    <xs:attribute name="country" type="countryType" use="required"/>
    <xs:attribute name="variant" type="variantType" use="optional"/>
</xs:complexType>
</xs:schema>

XML模式包含兩個選擇:fixedwidth或delimited,都具有語言環境類型。 為了清楚起見,省略了該架構的其余部分。

綁定文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<jaxb:bindings jaxb:version="2.2" xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:xjc="http://jaxb2-commons.dev.java.net/basic/inheritance"
               schemaLocation="myschema.xsd" node="/xs:schema">    

    <jaxb:schemaBindings>
        <jaxb:package name="org.mylib.schema"/>
    </jaxb:schemaBindings>

    <jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
        <jaxb:class name="DelimitedSchema"/>
        <xjc:extends>org.mylib.schema.Schema</xjc:extends>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='FixedWidthSchemaType']">
        <jaxb:class name="FixedWidthSchema"/>
        <xjc:extends>org.mylib.schema.Schema</xjc:extends>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='LocaleType']">
        <jaxb:class name="locale" />
    </jaxb:bindings>
</jaxb:bindings>    

我的maven pom.xml文件如下所示:

...
<build>
    <resources>
        <resource>
            <directory>${pom.basedir}/src/main/resources</directory>
        </resource>
    </resources>

    <plugins>
        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.13.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                    <specVersion>2.2</specVersion>

                    <schemaDirectory>src/main/resources</schemaDirectory>
                    <schemaIncludes>
                        <schemaInclude>myschema.xsd</schemaInclude>
                    </schemaIncludes>

                    <bindingDirectory>src/main/resources</bindingDirectory>
                    <bindingIncludes>
                        <bindingInclude>dataschema.xjb</bindingInclude>
                    </bindingIncludes>

                    <generateDirectory>${project.build.directory}/generated-sources/jaxb2</generateDirectory>

                    <extension>true</extension>
                    <args>
                        <arg>-Xinheritance</arg>
                    </args>
                    <plugins>
                        <plugin>
                            <groupId>org.jvnet.jaxb2_commons</groupId>
                            <artifactId>jaxb2-basics</artifactId>
                            <version>1.11.1</version>
                        </plugin>
                    </plugins>
                    <!-- Generate lots of output -->
                        <verbose>true</verbose>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
...

XJC輸出以下生成的類:

  • DelimitedSchema擴展了Schema
  • FixedWidthSchema擴展架構
  • 語言環境
  • 對象工廠
  • 模式類型

SchemaType類如下所示:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SchemaType", propOrder = { "delimited", "fixedwidth"})
public class SchemaType {
    protected DelimitedSchema delimited;
    protected FixedWidthSchema fixedwidth;

    public DelimitedSchema getDelimited() {
        return delimited;
    }

    public void setDelimited(DelimitedSchema value) {
        this.delimited = value;
    }

    public FixedWidthSchema getFixedwidth() {
        return fixedwidth;
    }

    public void setFixedwidth(FixedWidthSchema value) {
        this.fixedwidth = value;
    }
}

現在最糟糕的是,編譯器(XJC)抱怨:

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] \mylib\target\generated-sources\jaxb2\org\mylib\schema\DelimitedSchema.java:[51,7] error: DelimitedSchema is not abstract and does not override abstract method isFixedWidth() in Schema
[ERROR] \mylib\target\generated-sources\jaxb2\org\mylib\schema\FixedWidthSchema.java:[51,7] error: FixedWidthSchema is not abstract and does not override abstract method isFixedWidth() in Schema
[INFO] 2 errors 
[INFO] -------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] -------------------------------------------------------------

我遇到的問題是:

  1. 如何使用在其中實現這些方法的外部綁定文件將Schema的抽象方法實現到JAXB FixedWidthSchema和DelimitedSchema生成的類中? 我需要為每個生成的類在每個抽象方法中放入特定的代碼。
  2. 如何將生成的SchemaType類集成到Schema類中? 換句話說:我希望對Schema類進行編組/解組,以在XML文件中生成帶分隔符或固定寬度的標記,並在Schema中具有SchemaType的受保護成員。
  3. 是否有可能使所有生成的類及其方法包私有? 我想對用戶屏蔽這些生成的類(不使其成為公共API的一部分)

到目前為止,我還沒有找到解決這些問題的方法。 可能嗎? 還是我在尋找無法使用JAXB 2.x創建的不可能的解決方案?

想要的解決方案:

我的解決方案思想朝着進行編組和解組的Schema類的方向發展,Schema知道要編組/解組的方案。 派生類實現需要由Schema類定義的方法。

朝正確方向提供的任何幫助/建議都受到高度贊賞。

更新:

抽象的Schema類(這是一個非生成的類)與生成的類FixedWidthSchema和DelimitedSchema有關系。 DelimitedSchema是-架構,FixedWidthSchema是-架構。 因此,定義為抽象類的Schema接口是用戶需要使用/使用的唯一接口。 用戶不需要知道架構的內部細節,無論是固定寬度架構還是定界架構,對於用戶而言並不重要,僅對於我正在編寫的代碼而言。 該代碼可以通過調用isFixedWidth()或isDelimited()方法來確定它是哪種模式。 用戶只需要引用接口Schema,而不必引用任何FixedWidthSchema或DelimitedSchema實例。 從用戶的角度來看,這是隱藏的。 我面臨的問題是,我可以從手寫的Schema類擴展生成的類FixedWidthSchema或DelimitedSchema,但是現在手寫的模式不包含生成的SchemaType類,用於編組/取消編組<delimited>或<fixedwidth> XML源中的元素。 沒有生成的SchemaType類,我將無法封送/解組xml數據。 這就是為什么我要尋找一種將SchemaType類“集成”到手寫Schema類中的解決方案,以便我可以做到這一點的原因:

File f = new File("path/to/my/xmlfile.xml");
Reader r = new FileReader(f);
Schema sch = Schema.unmarshal(r);
// somewhere in other code parts:
if (sch.isDelimited()) {
   DelimitedSchema delSch = (DelimitedSchema)sch;
}
// or...:
if (sch.isFixedWidth()) {
   FixedWidthSchema fwSch = (FixedWidthSchema)sch;
}

現在,內部代碼可以訪問強制轉換模式的特定方法,從而解決該特定模式的獲取者/設置者。

通常,用戶不需要了解架構的內部,因為代碼本身將通過內部轉換為“正確的”類來處理固定寬度或定界之間的差異。

用戶僅對以下方法調用之一感興趣:

// To get a Schema instance (either fixedwidth or delimited) by unmarshalling a XML file.
Schema sch = Schema.unmarshal(aReader);
// Marshal the current schema instance to a XML file, using a Writer.
Writer wtr = sch.marshal();
// Create a schema instance by providing a Model on which the schema is based. This can be a fixedwidth or delimited Model.
Schema sch = Schema.create(m);
// Validate the schema if there are no errors.
sch.validate();

注意:我不希望SchemaType類以has-a關系包含在Schema類中。 我希望它是基類/超類架構與派生和生成的FixedWidthSchema或DelimitedSchema之間的is-關系。 我認為至少在普通的Java代碼中是可行的,但問題是:如何使用JAXB生成的類來實現這一點? 這是我還沒有弄清楚如何執行此操作的部分。

我也很好奇如何編寫一個JAXB插件,該插件將類和方法修飾符的訪問修飾符從public修改為package-private。

感謝您的所有幫助,因為這對我來說是一個真正的JAXB難題。 在普通(非生成)代碼中,這很容易編寫。

額外:

定界和固定寬度XML文件的內容。

分隔的XML:

<?xml version="1.0" encoding="utf-8"?>
<dataschema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <delimited>  <-- should be handled in Schema.java and not in SchemaType.java
    <locale language="en" country="en" />
  </delimited>
</dataschema>

FixedWidth XML:

<?xml version="1.0" encoding="utf-8"?>
<dataschema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <fixedwidth>  <-- should be handled in Schema.java and not in SchemaType.java
    <locale language="en" country="en" />
  </fixedwidth>
</dataschema>

fixedwidth和定界模式不一樣! 我忽略了所有其他元素,以使示例XML文件在StackOverflow上的此問題保持在最低限度。

解決方案

AFAIK,我設法在代碼和思想中解決了一些怪癖。 這些是寶貴的經驗教訓:

  • 不要創建必須從其擴展JAXB生成的類的非生成的抽象Java基類/超類。 因此,手寫Java類和生成的類之間沒有繼承!

  • 代替繼承,使用建議的JAXB使用代碼注入
    如果確實需要,請使用lexicore用戶提供的插件!

  • 使用以下設置,代碼注入可與Maven一起使用(請參閱
    以上為配置上下文):

    <參數>
    <arg> -Xinject代碼</ arg>
    </ args>

  • 除了繼承或代碼注入外,還應盡可能避免在代碼生成的類中使用這些機制。 僅在作為數據容器查看/使用生成的類時不需要它們。

  • 區分業務數據類和業務邏輯類。 例如:模式類僅保存要與模型類進行編組和解組的數據。 模型類保存數據以及應用程序用來處理數據的實際方法。 模式類是JAXB生成的類。 模型類是手寫類。

  • 使生成的類盡可能簡單,並最好使用外部綁定文件(* .jxb)修改生成的類。 例如:重命名類名稱,指定XmlAdapter類進行轉換,等等。

  • 要解決不將@XmlRootElement批注添加到基/根生成的類的問題,請確保您將基/根元素的complexType嵌入為XSD中的匿名complexType。 請注意,@ XMLRootElement僅會為頂級元素的匿名類型而不是頂級類型生成!

  • 在該領域(JAXB)的經驗豐富的開發人員為您提供建議時,請聽聽他們的忠告。 當解決方案很簡單時,不要試圖變得“聰明”。

結論:將業務邏輯從生成的代碼中移開!

最終結果很簡單(在DataModel類中):

  1. 在從DataModel分類的派生類中創建構造函數:public FixedWidthDataModel()或public DelimitedDataModel();
  2. public Writer marshal(),它將當前的DataModel對象(FixedWidth或Delimited)編組到Writer輸出中。
  3. 公共靜態DataModel解組(Reader r),它將提供的Reader輸入解組到一個(FixedWidth或Delimited)DataModel對象(input = XML文件)。
  4. public void validate(),用於驗證DataModel。
  5. public boolean isFixedWidth(),它指示DataModel是否為固定寬度的DataModel。
  6. public boolean isDelimited(),它指示DataModel是否為帶分隔符的DataModel。

現在,所有生成的架構類僅在DataModel的marshal()和unmarshal()方法內部使用。 這使得DataModel API獨立於所生成的類,因此在開發過程中稍后修改XML模式或所生成的類時,不會出現接口問題。

那是所有人。

對於1,您可以使用Code Injector插件。 看到這個問題

對於2,我無法理解“將生成的SchemaType類集成到Schema類中”的含義。

對於3-是的,使用您自己的XJC插件,但是可能有點困難。 :)

一個建議:將模式派生的類僅用作DTO,不要嘗試在其中施加過多的業務邏輯。

更新資料

仍然很難理解您想要實現的目標。 您用所有這些“ is-a”和“ has-a”解釋了您想為用戶做什么,但仍不清楚“集成”是什么意思。

另一方面,整個故事簡化為以下問題:

現在生成哪些代碼,並且您想生成哪些代碼?

那是核心。 如果回答了這個問題,您將遇到可以回答的編程問題。 現在,您僅描述您的用例,並期望有人為您設計解決方案。

據我了解,您只希望架構派生的類DelimitedSchemaFixedWidthSchema實際實現(或擴展)您的基類Schema 那么,為什么不這樣做呢? 使用xjc:extends (或JAXB繼承插件),您可以輕松地使DelimitedSchemaFixedWidthSchema擴展Schema 您的Schema類可能是一個抽象類,它定義了幾個只能由特定實現實現的抽象方法。

這可以通過使用Code Injector插件注入代碼來完成。 您只需將Schema類中抽象方法的實現注入到DelimitedSchemaFixedWidthSchema類中即可。 然后,可以將這些類的實例作為Schema實現返回給用戶。

讓我感到困惑的是,您實際上已經知道所有這些要素。 您了解xjc:extends ,代碼注入等。 什么東西少了?

最后,一些建議。

  • 如前所述,您最好將模式派生的類僅用作DTO。 將模式派生的代碼與業務邏輯集成在一起通常會導致無法維護的混亂。 您最好對業務類進行干凈的建模,並從DTO向它們復制數據。 這似乎首先需要更多工作,但稍后會有所收獲。 例如,當您需要並行支持多個版本的交換架構時。 您說“正常代碼將是小菜一碟”的事實是一種症狀。 您正在努力使代碼生成變得智能化,但也許應該讓它變得愚蠢。
  • 最好不要將非unmarshal / marshal方法轉移到商務艙。 將序列化與業務模型分開。 實現一個單獨的SchemaReader或類似的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM