問題抽象方法:實現從所產生JAXB類(繼承)抽象java類
我有稱爲架構的基類,它是抽象的,它是一種非生成的類。我有兩個從Schema繼承的生成的JAXB類:FixedWidthSchema和DelimitedSchema。
我使用外部綁定(xjb)文件來指定XSD和Java類之間的映射。
在基礎類模式,我已經定義的幾種方法:
- 公共模式靜態創建(型號M),其產生從設置模型的 一個Schema。
- public abstract Writer marshal(),它將當前的Schema對象(FixedWidth或Delimited)編組到編寫器輸出中。
- public Schema unmarshal(Reader r),它將提供的Reader輸入解組到一個Schema對象(input = XML文件)。
- public abstract void validate(),驗證創建的Schema。
- public abstract boolean isFixedWidth(),它表示創建的模式是否爲固定寬度模式。
- 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] -------------------------------------------------------------
是我遇到的問題是:
- 如何將Schema的抽象方法實現到生成的JAXB FixedWidthSchema和DelimitedSchema中使用我實現這些方法的外部綁定文件的類?我需要將特定的代碼放入每個基因處理類的每個抽象方法中。
- 如何將生成的SchemaType類集成到Schema類中?換句話說:我希望將Schema類編組/解組,它們在XML文件中生成分隔符或固定寬度標記,並在Schema中擁有SchemaType的受保護成員。
- 是否有可能將所有生成的類及其方法打包爲私有?我想屏蔽這些從用戶生成的類(不使它們成爲公共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的類):
- 創建從DataModel中導出歸類構造:公共 FixedWidthDataModel(),或公共DelimitedDataModel();
- public Writer marshal(),它將當前的DataModel對象(FixedWidth或Delimited)編組到編寫器輸出中。
- public static DataModel unmarshal(Reader r),它將提供的Reader輸入解組到一個(FixedWidth或Delimited)DataModel對象(input = XML文件)。
- public void validate(),它驗證DataModel。
- public boolean isFixedWidth(),它表示DataModel是否爲固定寬度DataModel。
- public boolean isDelimited(),它指示DataModel是否是分隔的DataModel。
所有生成的模式類現在只能在DataModel的marshal()和unmarshal()方法內部使用。這使DataModel API獨立於生成的類,因此在開發過程中稍後修改XML模式或生成的類時,不會出現接口問題。
這就是所有人。
對於#2:我的意思是將生成的SchemaType類(代表分隔和固定寬度的xml標籤)與我自己的'普通'java類Schema集成,以便我可以在這個對象上調用marshall()調用靜態unmarshall()爲我提供從Schema類中創建的Schema,該Schema類包含分隔或固定寬度的派生類。我希望我能更清楚地知道你在我的腦子裏發生了什麼:) – user504342
@ user504342不,對不起。顯示你想要工作的代碼。 – lexicore
我剛更新了更詳細的問題。我希望這可以讓我們更容易理解非生成和生成的類之間的目標:將它們混合在一起,以便獲得上述解決方案。 – user504342