2015-06-16 35 views
5

Sto lavorando a un'applicazione che utilizza XJC per generare POJO Java da XSD. Ci sono dozzine di schemi e quel numero crescerà. L'applicazione deve anche essere in grado di gestire diverse versioni dello stesso schema, il che significa che avrò più schemi che definiscono tipi comuni. Sto cercando di personalizzare i binding in modo che alcuni tipi di core implementino un'interfaccia comune. Il plugin Inheritance di JAXB2 Nozioni di base sembra fare ciò di cui ho bisogno, ma non riesco a trovare la giusta sintassi.JAXB ha generato classi di determinati tipi che implementano un'interfaccia personalizzata

Ecco la parte rilevante del mio schema:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:my="http://example.com/core" 
      targetNamespace="http://example.com/core" 
      xmlns:xml="http://www.w3.org/XML/1998/namespace"> 

    ... 

    <xs:complexType name="addressType"> 
     <xs:sequence> 
      <xs:element name="Address" type="xs:string"/> 
      <xs:element name="City" type="xs:string"/> 
      <xs:element name="Province" type="xs:string"/> 
      <xs:element name="Country" type="xs:string"/> 
      <xs:element name="County" type="xs:string" minOccurs="0"/> 
      <xs:element name="PostalCode" type="xs:string"/> 
     </xs:sequence> 
    </xs:complexType> 

    ... 

</xs:schema> 

... e questo è ciò che il mio file di collegamento personalizzato appare come:

<?xml version="1.0"?> 
<jaxb:bindings 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
    xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance" 
    xmlns:my="http://example.com/core" 
    jaxb:extensionBindingPrefixes="inheritance" 
    version="2.1"> 

    <jaxb:bindings scd="x-schema::my" xmlns:my="http://example.com/core"> 
     <jaxb:globalBindings localScoping="toplevel"> 
      <jaxb:serializable/> 
      <xjc:simple/> 
     </jaxb:globalBindings> 
     <jaxb:bindings scd="/type::my:addressType"> 
      <inheritance:implements>com.mysite.validator.ValidatableAddress</inheritance:implements> 
      <!--<xjc:superInterface name="com.mysite.validator.ValidatableAddress"/>--> 
     </jaxb:bindings> 
    </jaxb:bindings> 

</jaxb:bindings> 

sto usando il SCD approccio , poiché in tutti gli esempi di binding "tradizionali" che mostrano come utilizzare il plug-in di ereditarietà, viene specificato schemaLocation. Voglio evitare di dover specificare schemaLocation a causa del nostro grande (e crescente) numero di schemi. Non voglio dover modificare il file di bind ogni volta che aggiungiamo un nuovo schema. Quindi, scd sembra che soddisferà questo requisito.

Tuttavia quando si esegue la build utilizzando il sopra vincolante, ottengo questo:

[xjc] [ERROR] cvc-elt.1: Cannot find the declaration of element 'inheritance:implements'. 
    [xjc] line 18 of file:/dev/workspace/my_app/etc/schemas/bindings-common.xml 
    [xjc] failure in the XJC task. Use the Ant -verbose switch for more details 
    [xjc] classLoader = [email protected] 
    [xjc] SharedSecrets.getJavaNetAccess()[email protected] 

Se commento fuori l'eredità : implementa linea e rimuovere il commento xjc: superinterfaccia linea, l'errore va via e la compilazione viene completata correttamente, ma le mie classi Indirizzo non implementano il tipo ValidatableAddress.

È possibile utilizzare il plug-in dell'ereditarietà con scd? Può xjc: superInterface essere limitato solo a determinati elementi?

Cheers.

risposta

4

Grazie al lessico per le risposte rapide e dettagliate. Comunque quell'approccio non funzionava per me, così ho finito con la seguente soluzione ...

Poiché sto usando Ant per invocare XJC, ho finito per sfruttare le capacità di Ant <copy filtering="true"...> per generare dinamicamente il file di bind.

Ecco il mio file di collegamento "template" (binding-common.xml):

<?xml version="1.0"?> 
<jaxb:bindings 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
    xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance" 
    xmlns:my="http://http://example.com/core" 
    jaxb:extensionBindingPrefixes="inheritance" 
    version="2.1"> 
    <jaxb:bindings> 
     <jaxb:globalBindings localScoping="toplevel"> 
      <jaxb:serializable/> 
      <xjc:simple/> 
     </jaxb:globalBindings> 
    </jaxb:bindings> 

    <jaxb:bindings 
     schemaLocation="@[email protected]" 
     node="/xs:schema"> 

     <jaxb:bindings node="//xs:complexType[@name='addressType']"> 
      <inheritance:implements>com.example.validator.ValidatableAddress</inheritance:implements> 
     </jaxb:bindings> 
    </jaxb:bindings> 

</jaxb:bindings> 

Nota questa riga:

<jaxb:bindings 
      schemaLocation="@[email protected]" 
      node="/xs:schema"> 

Questa variabile sarà ottenere popolato da Ant per ciascuno degli schemi che sto elaborando:

<property name="jaxb.binding.template" value="../etc/form-schemas/bindings-common.xml"/> 
<property name="jaxb.binding.file" value="${jaxb.src.dir}/bindings-common${schema.version}.xml"/> 

<echo message="Filtering ${jaxb.binding.file} using template ${jaxb.binding.template}"/> 

<copy file="${jaxb.binding.template}" 
     tofile="${jaxb.binding.file}" 
     filtering="true"> 

    <filterset> 
     <filter token="bindingSchema" value="../../etc/form-schemas/${schema.version}/common.xsd"/> 
    </filterset> 
</copy> 

<xjc destdir="${jaxb.src.dir}" 
     extension="true" 
     schema="${schema.file}" 
     package="${package}" 
     binding="${jaxb.binding.file}"> 

    <arg value="-episode"/> 
    <arg value="${jaxb.src.dir}/common${schema.version}.episode"/> 
    <arg line="-Xinheritance"/> 

     <!-- Plugins --> 
     <classpath> 
      <fileset dir="../build-libs/"> 
       <!-- JAXB2 Basics library --> 
       <include name="jaxb2-basics-0.6.4.jar"/> 
       <!-- JAXB2 Basics library dependencies --> 
       <include name="jaxb2-basics-runtime-0.6.4.jar"/> 
       <include name="jaxb2-basics-tools-0.6.4.jar"/> 
       <include name="javaparser-1.0.8.jar"/> 
       <include name="commons-beanutils-*.jar"/> 
       <include name="commons-lang-*.jar"/> 
       <include name="commons-logging-*.jar"/> 
      </fileset> 
     </classpath> 
    </xjc> 
</target> 

Speriamo che questo aiuti le future generazioni di vittime JAXB.

4

Autore di qui.

Vedere this issue in XJC. In breve, XJC per qualche motivo non consente gli elementi di personalizzazione personalizzati/fornitori nei collegamenti SCD.
inheritance:implements è un elemento di personalizzazione.

Quindi no, questo non funziona a causa di un problema in XJC.

Personalmente leggo via schemaLocation e XPath ma uso un URI di posizione dello schema "virtuale" e lo riscrivo tramite cataloghi.

SCD sarebbe stata una scelta molto migliore (sei assolutamente proprio qui) ma semplicemente non funziona.

Aggiornamento sulla posizione dello schema virtuale e cataloghi.

Ecco un example of binding che personalizza un certo tipo complesso:

<jaxb:bindings 
    schemaLocation="http://schemas.opengis.net/wps/2.0/wpsCommon.xsd" 
    node="/xs:schema"> 
    <jaxb:bindings node="xs:element[@name='Data']/xs:complexType"> 
     <wildcard:lax/> 
    </jaxb:bindings> 
</jaxb:bindings> 

Si è legato tramite schemaLocation e XPath. Il schemaLocation è un existing URL, ma nella build che viene riscritto via catalog nella risorsa all'interno di un manufatto Maven:

REWRITE_SYSTEM "http://schemas.opengis.net" "maven:org.jvnet.ogc:ogc-schemas:jar::!/ogc" 

Quindi, in pratica http://schemas.opengis.net/wps/2.0/wpsCommon.xsd sarà caricato dal ogc-schema.jar!/ogc/wps/2.0/wpsCommon.xsd.

Utilizzando è possibile refer to binding files inside Maven artifacts as well:

    <binding> 
         <dependencyResource> 
          <groupId>${project.groupId}</groupId> 
          <artifactId>ows-v_2_0</artifactId> 
          <resource>ows-v_2_0.jsonix.xjb</resource> 
          <version>${project.version}</version> 
         </dependencyResource> 
        </binding> 

Così, in combinazione, permette la scrittura di file vincolanti una volta e riutilizzarli in tutta moduli.

Ma questo era tutto un dolore enorme da capire. L'ho fatto per il progetto ogc-schemas che ora è composto da 50 schemi fortemente interconnessi. Soffro pesantemente di inconvenienti e problemi XJC, ma questo è il migliore possibile al momento. Ho persino pensato a forking and patching XJC, ma questo è uno dei limiti di sforzo che posso permettermi.

Quindi ho finito con un certo numero di soluzioni alternative di mindblogging che in qualche modo fanno il lavoro alla fine della giornata.

+0

Grazie lessical. Che ne dici di combinare scd e xjc: superInterface ... Dovrebbe funzionare? Qualche idea sul perché questo approccio non genera errori, ma non sembra avere alcun effetto sulla sorgente generata? – 6006604

+0

... oppure xjc: superInterface considera una personalizzazione personalizzata/del fornitore proprio come l'ereditarietà: implementazioni? – 6006604

+0

In realtà è un'estensione fornitore ma è un'estensione fornitore "di prima classe" che è specificamente nota a XJC (vedere [qui] (https://github.com/gf-metro/jaxb/blob/69471fb27af6a9e990ef2a7873aab64a18e87640/jaxb-ri/ xjc/src/main/resources/com/sun/tools/xjc/reader/xmlschema/bindinfo/binding.xsd # L81)) - a differenza di "inheritance: implements". A proposito, non è 'xjc: superInterface' per [solo collegamenti globali] (https://jaxb.java.net/nonav/2.1.15/docs/vendorCustomizations.html#superinterface)? Spiegherebbe perché è ignorato nella classe. – lexicore