Ho questa API che utilizza JAXB per utilizzare convenientemente modelli di oggetti, generati da schemi XML dal compilatore XJC (XML-to-Java), attraverso riferimenti nominati. Estrae la creazione di contesti JAXB e trova i metodi ObjectFactory lontani da ogni sorta di magia di sfondo e riflessione. L'essenza di base è che si dovrebbe sempre definire uno schema generale, e quindi qualsiasi numero (può anche essere 0) di schemi che "estendano" quello generale, ciascuno risultante nel proprio modello di dati. Lo schema generale contiene le definizioni riutilizzabili, quelle che lo estendono usano quelle per comporre i propri modelli.Impossibile risolvere le definizioni di tipo dallo schema importato in XJC
Ora mi trovo nella situazione in cui vorrei riutilizzare lo schema generale per più di un progetto. Le definizioni di tipo generale dovrebbero rimanere invariate tra i progetti e alcuni codici verranno creati in base alle classi astratte generate da tali elementi. Quindi dovrei prima generare le classi per alcuni schemi generici, quindi generare quelle estendendole e usandole separatamente. Sto usando Maven per il mio processo di compilazione.
Il problema che sto incontrando è la risoluzione delle definizioni di tipo da quello schema generico negli schemi di estensione.
Suppongo che la mia schema generico si chiama "general.xsd" e si presenta così:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Element (will usually be root) -->
<xs:element name="transmission" type="gen:Transmission" />
<!-- Definition -->
<xs:complexType name="Transmission" abstract="true">
<xs:sequence>
<!-- Generic parts of a transmission would be in here... -->
</xs:sequence>
</xs:complexType>
</xs:schema>
Accanto a che c'è un file di binding per fare un po 'di personalizzazione di denominazione e impostare il nome del pacchetto per l'uscita:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for the general schema -->
<bindings schemaLocation="general.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.general"/>
</schemaBindings>
<bindings node="//xs:complexType[@name='Transmission']">
<!-- Some customization of property names here... -->
</bindings>
</bindings>
mi piacerebbe poi hanno il bit successivo nel POM di quel progetto per generare le classi Java:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>true</episode>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
Come potete vedere, sto usando il plugin Maven JAXB2.1. Ho impostato l'opzione per generare un file episodio per la compilazione step-wise. L'opzione per rimuovere l'output precedente era per una soluzione di bug; tutto ciò che fa è assicurarsi che tutto sia stato ripulito per primo, in modo che la ricompilazione sia forzata.
Fin qui tutto bene. Questo progetto si compila senza intoppi. Va notato che oltre alle classi Java generate, impacchetta anche gli schemi nel file jar risultante. Quindi quelli sono disponibili sul classpath! Il file sun-jaxb.episode
si trova nel META-INF, come dovrebbe essere.
Quindi avvio il progetto che utilizza schemi che estenderanno il precedente, prima di importarlo. Uno dei "sottotipi" potrebbe assomigliare a questo (lo chiamerò sub.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:import namespace="http://www.foobar.com/general" />
<!-- Definition -->
<xs:complexType name="SubTransmission">
<xs:complexContent>
<xs:extension base="gen:Transmission">
<xs:sequence>
<!-- Additional elements placed here... -->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Anche in questo caso, c'è un file di binding:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for sub type -->
<bindings schemaLocation="sub.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.sub"/>
</schemaBindings>
</bindings>
</bindings>
Ed ecco che la punta del POM di questo progetto, che si prende cura del XJC generazione:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>false</episode>
<catalog>${basedir}/src/main/resources/com/foobar/schemas/catalog.cat</catalog>
<episodes>
<episode>
<groupId>com.foobar</groupId>
<artifactId>foobar-general-models</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</episode>
</episodes>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
in origine, tutti gli schemi erano in una singola cartella e ho avuto l'attributo schemaLocation
nell'importazione impostato general.xsd
, che Espirimento del Furto d bene. Ma ora che le cose sono separate tra i progetti, mi imbatto in problemi. Il primo problema è che non è stato possibile trovare l'altro schema. L'ho risolto prendendo l'attributo schemaLocation
dall'elemento <xs:import />
, mantenendo solo l'attributo namespace
e aggiungendo un file di catalogo (catalog.cat
) che è possibile vedere come indicato nell'estratto POM precedente.I suoi contenuti sono:
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
Questo sembra funzionare, dal momento che non è più ottenere un errore che indica lo schema non può essere trovato. Ma per qualche ragione, la risoluzione delle definizioni dei tipi effettive dallo schema importato continua a fallire. Ecco l'eccezione:
Error while parsing schema(s).Location [ file:/C:/NetBeans_groups/Test/SubModelBundle/src/main/resources/com/foobar/schemas/sub.xsd{...,...}].
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'gen:Transmission' to a(n) 'type definition' component.
Ecco quello che ho provato finora:
- Utilizzare un file di catalogo. Parzialmente riuscito, poiché ora è possibile trovare lo schema importato.
- La compilation per lo schema generale genera un file episodio e lo utilizza per la compilazione dello schema secondario. Non sembra fare la differenza, anche se questo dovrebbe giocare un ruolo solo una volta che il tipo è stato risolto, quindi non penso che questo sia ancora importante.
- Utilizzare una JAXP diversa (nota: non JAXB, JAXP) implementazione. Ne ho usato uno diverso, perché ho potuto vederlo nella traccia dello stack dell'eccezione, ma il risultato finale è lo stesso.
- Utilizzare
maven-jaxb22-plugin
anziché 21. Nessuna differenza.
Guardando intorno online, sembra che le persone sono state in esecuzione in questo problema almeno dal 2006 e che potrebbe essere correlato ad alcuni problemi resolver xerces. Spero che questo non sia un bug in agguato da 6 anni senza che nessuno si preoccupi di risolverlo. Qualcun altro ha qualche suggerimento? Forse qualcuno si è imbattuto nello stesso problema e ha trovato una soluzione? L'unica soluzione che posso pensare è usare 'svn: externals' per trascinare lo schema generale nel sottoprogetto e rigenerare semplicemente le classi lì, ma è sporco e funzionerà solo quando è possibile connettersi al nostro repository SVN.
Molto grazie in anticipo per aver letto questo lungo post. Tieni presente che ho preso tutto quanto sopra dai progetti esistenti e ho sostituito alcuni spazi dei nomi e altre cose per l'anonimato, quindi alcuni errori di battitura sono possibili.
Sto avendo gli stessi problemi. +1 per una domanda ben documentata. – KingAndrew