2010-12-29 13 views
6

potrzebujesz pomocy w następującej sytuacji: Użytkownicy mogą generować własne struktury danych, które są przechowywane jako JAXB gotowe źródła XSD jak poniżej:jak zmusić klas schematu opracowano rozszerzenie konkretnej klasy poza schemat

<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> 

Po nowy lub zmodyfikowany schemat pojawia się ona automatycznie analizowany przez kompilator, źródeł java schema jest generowany, opracowany i pakowane w słoiki użytkowniczki:

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 
    // ...... 

i wszystko było w porządku, dopóki nie zdecydowano, że wszystkie klasy generowane przez użytkownika muszą rozciągać jeden konkretny znanej klasy, powiedzmy UserRootObject:

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

i

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

Wszystko jest na bieżąco, nie mogę zmusić użytkowników do modyfikacji plików schematu, ale mogę przekształcić je przed generowania kodu. Wygląda na to, że mam dwie możliwości wprowadzenia tego UserRootObject: w jakiś sposób poprzez JCodeModel lub jakoś transformacji plików schematu przed budowaniem źródeł Java.

Odpowiedz

1

Nie sądzę, że istnieje prosty sposób, aby to zrobić za pomocą samego JAXB. Istnieje wiele dostępnych opcji dostosowywania, które nie są powszechnie znane - przeczytaj section 7 of JSR222, aby uzyskać szczegółowe informacje.

Jeśli masz pewną kontrolę nad schematami wejściowymi, możesz rozważyć użycie XSLT do transformacji schematu. Uważam, że można to zrobić, używając instancji javax.xml.transform.dom.DOMResult jako celu transformacji i wykorzystując dane wyjściowe jako drzewo DOM (np. Wywołując getNode() na wyniku) jako dane wejściowe do parseSchema. Podstawowa przemiana byłoby wymienić:

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

z czymś takim:

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

Oczywiście działa to tylko w prostych przypadkach. Jeśli masz już dziedziczenie w plikach schematu, będziesz musiał wykonać pewne filtrowanie w XSLT, które stosuje tę transformację tylko do typów, które jeszcze nie są rozszerzone.

+0

Dzięki! Tak, mógłbym zmienić schemat w ten sposób, ale jak mogę powiedzieć kompilatorowi schematu, aby nie generował UserRootObject, ale raczej "odwoływał się" do istniejącej klasy? Czy to w ogóle możliwe? Byłoby świetnie i rozwiązało problem. – Osw

+1

Masz rację w tym standardzie JAXB nie obejmuje tego przypadku użycia, ale XJC oferuje to jako rozszerzenie. Aby uzyskać więcej informacji, zobacz: http://stackoverflow.com/questions/4556179/how-to-force-schema-compiled-classes-to-extend-specific-class-outside-schema/4607476#4607476 –

5

Podziękowania dla D.Shawley za wskazanie właściwej sekcji w JSR 222. Oto ostateczne rozwiązanie, które może być pomocne i oszczędzać czas dla kogoś innego. Original schematu musi zostać przekształcona w następujący sposób:

<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> 

Transformacja można łatwo przeprowadzić poprzez org.w3c.dom.Document inteface.

7

XJC ma rozszerzenie do tego celu

<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> 

Aby uzyskać więcej informacji, patrz:

Adnotacje schematu może być również zasilany za pomocą pliku wiązaniami zewnętrznego.Na przykład patrz:

+0

Dobre rozwiązanie. Szkoda, że ​​tu nie byłeś w 2010 roku :) Osobiście wolę trzymać się specyfikacji JAXB i nie polegać na implementacji XJC, ale rozwiązanie może być bardzo przydatne i oszczędzać czas innym. Przy tym wspomniany tryb "-rozszerzania" jest nieco mylący, trzeba będzie sprawdzić, czy ten tryb jest włączony dla kompilacji w locie, tak jak w moim przypadku. – Osw