2016-11-04 175 views
0

問題抽象方法:實現從所產生JAXB類(繼承)抽象java類

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

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

在基礎類模式,我已經定義的幾種方法:

  1. 公共模式靜態創建(型號M),其產生從設置模型的 一個Schema。
  2. public abstract Writer marshal(),它將當前的Schema對象(FixedWidth或Delimited)編組到編寫器輸出中。
  3. public Sc​​hema unmarshal(Reader r),它將提供的Reader輸入解組到一個Schema對象(input = XML文件)。
  4. public abstract void validate(),驗證創建的Schema。
  5. public abstract boolean isFixedWidth(),它表示創建的模式是否爲固定寬度模式。
  6. public abstract boolean isDelimited(),它表示創建的模式是否是分隔模式。

我想要在生成的jaxb類FixedWidthSchema和DelimitedSchema中實現抽象方法(2,4,5和6)。兩者都擴展了基類Schema。因此,當我調用Schema.isFixedWidth()時,基礎繼承類將響應此調用並告知調用者:true/false。只有派生類知道他們是誰:固定寬度或分隔符。

這裏是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架構包含兩個選擇:固定寬度或帶分隔符,都有一個區域類型。爲了清楚起見,省略了架構的其餘部分。

綁定文件看起來是這樣的:

<?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延伸架構
  • FixedWidthSchema延伸架構
  • 區域設置
  • 的ObjectFactory
  • 的SchemaType

的的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類定義的需要實現的方法。

任何在正確方向的幫助/建議是非常感謝。

UPDATE:

抽象模式類(其是非生成的類)具有相對於所述生成的類FixedWidthSchema和DelimitedSchema。 DelimitedSchema是一個Schema,FixedWidthSchema是一個Schema。因此,Schema接口(定義爲抽象類)是用戶需要使用/使用的唯一接口。用戶不需要知道架構的內部細節,無論是FixedWidth還是Delimited架構對於用戶來說都不重要,僅限於我正在編寫的代碼。代碼可以通過調用isFixedWidth()或isDelimited()方法來確定它是哪個模式。用戶只需要引用Schema接口,而不是任何FixedWidthSchema或DelimitedSchema實例。這從用戶的角度來看是隱藏的。我面臨的問題是,我可以從手寫的Schema類擴展生成的類FixedWidthSchema或DelimitedSchema,但是現在手寫的模式不包含生成的SchemaType類,它需要編組/解組編碼<分隔的>或<固定寬度> XML源中的元素。沒有生成的SchemaType類,我無法編組/解組XML數據。這就是爲什麼我要尋找的是「整合」的的SchemaType類進入手寫模式類的解決方案,這樣我可以做到這一點:

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類做。我希望它是基礎/超類綱要和派生和生成的固定寬度綱領或分隔綱領之間的一種關係。我認爲這是可能的,至少在正常的java代碼中,但問題是:如何使用JAXB生成的類來完成此操作?這是我還沒有弄清楚如何做到這一點的部分。

我也很好奇如何編寫一個JAXB插件,用於修改類和方法修飾符的公共訪問修飾符到包私有修飾符。

感謝您的幫助,因爲這對我來說是一個真正的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> 

固定寬度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> 

的固定寬度和分隔的模式是不一樣的!我省略了所有其他元素,以便在StackOverflow上將此示例XML文件保留爲最小值。

的解

據我所知,我設法解決一些怪癖在我的代碼,並在我的思想。這些都是寶貴的經驗教訓:

  • 不要創建一個非產生抽象的Java基礎/這 的JAXB生成的類必須擴展超類。所以,在手寫java類和生成的類之間沒有繼承 !

  • 代替繼承,使用代碼注入使用建議的JAXB
    插件由用戶lexicore,如果真的需要!

  • 代碼注入使用以下設定的Maven工作(見上文
    用於配置上下文):

    <ARGS>
          <ARG> -Xinject碼</ARG >
    </args >

  • 代替繼承或代碼注入,應儘可能避免在代碼生成的類中使用這些機制。他們是 當看到/使用生成的類僅作爲數據容器的數據 時不需要。

  • 讓您的業務數據類和業務邏輯 類之間的區別。例如:模式類只能將數據編組爲 編組和從模型類解組。模型 類保存數據以及應用程序操縱的數據爲 的實際方法。架構類是JAXB生成的 類。模型類是手寫類。

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

  • 爲了克服未添加@XmlRootElement註釋 鹼/根生成的類問題,請確保您有 複雜類型在XSD中作爲匿名 complexType嵌入的基本/根元素。請注意@XMLRootElement只會爲 生成,用於匿名類型的頂級元素,而不是頂級類型!

  • 在該特定字段(JAXB)中由經驗豐富的開發人員 給您聽取良好建議。當解決方案簡單時,不要試圖成爲'聰明'。

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

的endresult是簡單(在DataModel的類):

  1. 創建從DataModel中導出歸類構造:公共 FixedWidthDataModel(),或公共DelimitedDataModel();
  2. public Writer marshal(),它將當前的DataModel對象(FixedWidth或Delimited)編組到編寫器輸出中。
  3. public static DataModel unmarshal(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

對於1,您可以使用代碼注入器插件。請參閱this question

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

3 - 是的,用你自己的XJC插件,但它可能有點難。 :)

建議:只使用模式派生類作爲DTO,不要試圖推動那裏的業務邏輯。

更新

它仍然是一個有點難以瞭解你想要達到的目標。你解釋了你想爲你的用戶做什麼,所有這些都是「is-a」和「has-a」,但是你仍然不清楚「整合」是什麼意思。

從另一方面原委減少了以下問題:

哪個代碼現在生成你想要的代碼

中產生?

這就是核心。如果你回答這個問題,你會得到可以回答的編程問題。現在你只是描述你的用例,並期望有人爲你設計一個解決方案。

根據我的理解,您只是想讓您的架構派生類DelimitedSchemaFixedWidthSchema實際實現(或擴展)您的基類Schema。那麼,爲什麼你不這樣做呢?使用xjc:extends(或JAXB繼承插件),您可以輕鬆地使DelimitedSchemaFixedWidthSchema擴展爲Schema。您的Schema類可能是一個抽象類,它定義了幾個只能通過特定實現實現的抽象方法。

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

讓我感到困惑的是,你實際上已經知道所有這些元素。你知道xjc:extends,代碼注入等等。什麼不見​​了?

最後幾點建議。

  • 正如我之前提到的,您最好只使用模式派生類作爲DTO。將模式派生代碼與業務邏輯集成通常會導致無法維護的混亂。您最好乾淨地爲您的業務類型建模,並將數據從DTOs複製到其中。這可能看起來更多工作,但會在以後付清。例如,當你需要並行支持多個版本的交換模式時。你說「正常的代碼將是小菜一碟」是一個症狀。你正在努力使代碼生成變得聰明,但也許它應該是愚蠢的。
  • 最好不要移動unmarshal/marshal方法到商務類。保持序列化與業務模型分開。實施一個單獨的SchemaReader或類似的東西。
+0

對於#2:我的意思是將生成的SchemaType類(代表分隔和固定寬度的xml標籤)與我自己的'普通'java類Schema集成,以便我可以在這個對象上調用marshall()調用靜態unmarshall()爲我提供從Schema類中創建的Schema,該Schema類包含分隔或固定寬度的派生類。我希望我能更清楚地知道你在我的腦子裏發生了什麼:) – user504342

+0

@ user504342不,對不起。顯示你想要工作的代碼。 – lexicore

+0

我剛更新了更詳細的問題。我希望這可以讓我們更容易理解非生成和生成的類之間的目標:將它們混合在一起,以便獲得上述解決方案。 – user504342