2010-12-29 7 views
6

mit folgenden Situation Brauchen Sie Hilfe: Benutzer können ihre eigenen Datenstrukturen erzeugen, die im Folgenden als JAXB-ready XSD Quellen wie gespeichert werden:wie Schema kompilierten Klassen erzwingen außerhalb Schema spezifische Klasse erweitern

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xs:element name="Group" type="Group"/> 
    <xs:element name="Parameter" type="Parameter"/> 

    <xs:complexType name="Group"> 
    <xs:sequence> 
     <xs:element name="caption" type="xs:string" minOccurs="0"/> 
     <xs:element name="parameters" type="Parameter" nillable="true" minOccurs="0" maxOccurs="unbounded"/> 
    </xs:sequence> 
    </xs:complexType> 

    <xs:complexType name="Parameter"> 
    <xs:sequence> 
     <xs:element name="key" type="xs:string" minOccurs="0"/> 
     <xs:element name="group" type="Group" minOccurs="0"/> 
     <xs:element name="value" type="xs:string" minOccurs="0"/> 
    </xs:sequence> 
    </xs:complexType> 
</xs:schema> 

Nach neuem oder modifizierte Schema erscheint es automatisch von Schema-Compiler, java Quellen analysiert wird, erzeugt wird, kompiliert und in Benutzer Gläser verpackt:

SchemaCompiler sc = XJC.createSchemaCompiler(); 
    // Input source for schema 
    InputSource is = new InputSource(new StringInputStream(objectPackage.getObjectSchema())); 
    // Parse 
    sc.parseSchema(is); 
    S2JJAXBModel model = sc.bind(); 
    // Generate source 
    JCodeModel jCodeModel = model.generateCode(null, null); 
    jCodeModel.build(packageSourceDirectory); 
    // Compile and package 
    // ...... 

und alles war in Ordnung, bis es wurde beschlossen, dass alle Benutzer-generierten Klassen erweitern müssen eine bestimmte bekannte Klasse, sagt UserRootObject:

package user.abc; 
public class Group extends com.mycompany.xml.UserRootObject { 
    // 
} 

und

package user.abc; 
public class Parameter extends com.mycompany.xml.UserRootObject { 
    // 
} 

Alles on the fly ist, kann ich nicht Benutzer zwingen kann, ihre Schema-Dateien zu ändern, aber ich kann sie Generation vor Code umwandeln. Sieht so aus, als hätte ich zwei Möglichkeiten, um das UserRootObject einzuführen: Irgendwie über JCodeModel oder irgendwie Transformieren von Schemadateien vor dem Erstellen von Java-Quellen.

Antwort

1

Ich glaube nicht, dass es eine einfache Möglichkeit gibt, dies mit JAXB selbst zu tun. Es gibt eine Reihe von Anpassungsoptionen, die nicht allgemein bekannt sind - lesen Sie section 7 of JSR222 für Details.

Wenn Sie die Eingabeschemas steuern können, sollten Sie möglicherweise XSLT zur Transformation des Schemas in Betracht ziehen. Ich glaube, dass dies getan werden kann, indem eine javax.xml.transform.dom.DOMResult Instanz als das Ziel der Transformation verwendet wird und die Ausgabe als eine DOM-Struktur (z. B. getNode() auf dem Ergebnis) als die Eingabe zu parseSchema verwendet wird. Eine grundlegende Transformation wäre zu ersetzen:

<xs:complexType name="foo"> 
    <!-- CONTENTS --> 
</xs:complexType> 

mit so etwas wie:

<xs:complexType name="foo"> 
    <xs:complexContent> 
    <xs:extension base="UserRootObject"> 
     <!-- CONTENTS --> 
    </xs:extension> 
    </xs:complexContent> 
</xs:complexType> 

Natürlich funktioniert dies nur für die einfachen Fälle. Wenn Sie bereits Vererbung in Ihren Schemadateien haben, müssen Sie eine Filterung in der XSLT durchführen, die diese Transformation nur auf Typen anwendet, die nicht bereits erweitert sind.

+0

Dank! Ja, ich könnte das Schema auf diese Weise transformieren, aber wie kann ich dem Schema-Compiler mitteilen, dass er UserRootObject nicht erzeugen, sondern auf eine existierende Klasse verweisen soll? Ist es überhaupt möglich? Das wäre großartig und löse das Problem. – Osw

+1

Sie haben Recht, dass der Standard JAXB diesen Anwendungsfall nicht behandelt, aber XJC bietet dies als Erweiterung an. Für weitere Details siehe: http://StackOverflow.com/Questions/4556179/how-to-force-schema-compiled-Classes-to-Extend-Specific-Class-Outside-Schema/4607476#4607476 –

5

Vielen Dank an D.Shawley für den Hinweis auf den richtigen Abschnitt in JSR 222. Hier ist die endgültige Lösung, die hilfreich und zeitsparend für jemand anderen sein könnte. Original-Schema muss wie folgt transformiert werden:

<xs:schema version="1.0" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema" 
       xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
       jaxb:version="2.0" > 

     <xs:element name="Group" type="Group"/> 
     <xs:element name="Parameter" type="Parameter"/> 


     <xs:complexType name="Group"> 
     <xs:complexContent> 
      <xs:extension base="UserRootObject"> 
      <xs:sequence> 
      <!-- params --> 
      </xs:sequence> 
      </xs:extension> 
     </xs:complexContent> 
     </xs:complexType> 

     <xs:complexType name="Parameter"> 
     <xs:complexContent> 
      <xs:extension base="UserRootObject"> 
      <xs:sequence> 
      <!-- params --> 
      </xs:sequence> 
      </xs:extension> 
     </xs:complexContent> 
     </xs:complexType> 

     <xs:complexType name="UserRootObject"> 
     <xs:annotation> 
      <xs:appinfo> 
      <jaxb:class name="UserRootObject" implClass="com.mycompany.xml.UserRootObject"/> 
      </xs:appinfo> 
     </xs:annotation> 
     </xs:complexType> 
    </xs:schema> 

Transformation kann leicht über org.w3c.dom.Document inteface durchgeführt werden.

7

XJC hat eine Verlängerung für diesen Zweck

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
      xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
      jaxb:extensionBindingPrefixes="xjc" 
      jaxb:version="2.0"> 

    <xs:annotation> 
     <xs:appinfo> 
      <jaxb:globalBindings> 
      <xjc:superClass name="com.mycompany.xml.UserRootObject"/> 
      </jaxb:globalBindings> 
     </xs:appinfo> 
    </xs:annotation> 
. 
. 
. 
</xs:schema> 

Weitere Informationen finden Sie unter:

Die Schemaannotationen können auch über eine externe Bindungsdatei geliefert werden.Ein Beispiel finden:

+0

Schöne Lösung. Ich wünschte, du wärst hier im Jahr 2010 :) Persönlich bevorzuge ich es, bei JAXB zu bleiben und mich nicht auf die XJC-Implementierung zu verlassen, aber die Lösung könnte für andere sehr nützlich und zeitsparend sein. Übrigens ist der erwähnte "-Extension" -Modus etwas verwirrend, man muss prüfen, ob dieser Modus für die On-The-Fly-Schema-Kompilierung aktiviert ist, wie in meinem Fall. – Osw