[英]Implementing abstract methods from abstract java class in generated jaxb class (inheritance)
問題:
我有一個稱為Schema的基類,它是抽象的,它是一個非生成的類。 我有兩個從Schema繼承的生成的JAXB類:FixedWidthSchema和DelimitedSchema。
我使用外部綁定(xjb)文件來指定XSD和Java類之間的映射。
在基類Schema中,我定義了一些方法:
我希望在生成的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輸出以下生成的類:
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] -------------------------------------------------------------
我遇到的問題是:
到目前為止,我還沒有找到解決這些問題的方法。 可能嗎? 還是我在尋找無法使用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類中):
現在,所有生成的架構類僅在DataModel的marshal()和unmarshal()方法內部使用。 這使得DataModel API獨立於所生成的類,因此在開發過程中稍后修改XML模式或所生成的類時,不會出現接口問題。
那是所有人。
對於1,您可以使用Code Injector插件。 看到這個問題
對於2,我無法理解“將生成的SchemaType類集成到Schema類中”的含義。
對於3-是的,使用您自己的XJC插件,但是可能有點困難。 :)
一個建議:將模式派生的類僅用作DTO,不要嘗試在其中施加過多的業務邏輯。
更新資料
仍然很難理解您想要實現的目標。 您用所有這些“ is-a”和“ has-a”解釋了您想為用戶做什么,但仍不清楚“集成”是什么意思。
另一方面,整個故事簡化為以下問題:
現在生成哪些代碼,並且您想生成哪些代碼?
那是核心。 如果回答了這個問題,您將遇到可以回答的編程問題。 現在,您僅描述您的用例,並期望有人為您設計解決方案。
據我了解,您只希望架構派生的類DelimitedSchema
和FixedWidthSchema
實際實現(或擴展)您的基類Schema
。 那么,為什么不這樣做呢? 使用xjc:extends
(或JAXB繼承插件),您可以輕松地使DelimitedSchema
和FixedWidthSchema
擴展Schema
。 您的Schema
類可能是一個抽象類,它定義了幾個只能由特定實現實現的抽象方法。
這可以通過使用Code Injector插件注入代碼來完成。 您只需將Schema
類中抽象方法的實現注入到DelimitedSchema
和FixedWidthSchema
類中即可。 然后,可以將這些類的實例作為Schema
實現返回給用戶。
讓我感到困惑的是,您實際上已經知道所有這些要素。 您了解xjc:extends
,代碼注入等。 什么東西少了?
最后,一些建議。
unmarshal
/ marshal
方法轉移到商務艙。 將序列化與業務模型分開。 實現一個單獨的SchemaReader
或類似的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.