Generuj klasy Java z plików .XSD…?

127

Mam gigantyczny plik schematu .XSD SDK programu QuickBooks, który definiuje żądania / odpowiedzi XML, które mogę wysyłać / odbierać z programu QuickBooks.

Chciałbym mieć możliwość łatwego generowania klas Java z tych plików .XSD, których mógłbym następnie użyć do kierowania XML do obiektów Java, a obiektów Java do XML.

Czy jest na to łatwy sposób ...?

Idealnie byłoby, gdyby nie wymagał żadnych bibliotek zewnętrznych w stosunku do podstawowej dystrybucji Java w czasie wykonywania. Ale jestem elastyczny ...

Keith Palmer Jr.
źródło
6
Jeśli chcesz generować ręcznie, umieść plik .xsd w swoim projekcie eclipse, kliknij plik prawym przyciskiem myszy, a następnie naciśnij przycisk „generuj”
Junchen Liu

Odpowiedzi:

121

JAXB robi DOKŁADNIE to, co chcesz. Jest wbudowany w JRE / JDK począwszy od wersji 1.6

basszero
źródło
7
Niestety, ta funkcja nie będzie już dostępna od wersji Java 9. Wynika to z faktu, że odpowiednie klasy (w szczególności klasy com.sun.tools.xjc. *) Nie będą już dostępne za pośrednictwem JDK.
Marco
4
Nie sądzę, aby usunięcie tego z JDK było problemem, ponieważ projekt java.net (link w odpowiedzi) prawdopodobnie pozostanie.
stmoebius
1
Jak wyjaśniono w tym miejscu , zależności w języku Java 9 można dodać za pomocą argumentu wiersza poleceń lub dodać zależność ręcznie.
Matthias Ronge,
118

Aby rozwinąć powyższe komentarze „użyj JAXB”,

W systemie Windows "%java_home%\bin\xjc" -p [your namespace] [xsd_file].xsd

na przykład, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

Poczekaj chwilę, a jeśli masz dobrze sformułowany plik XSD, otrzymasz kilka dobrze sformułowanych klas Java

Ed Norris
źródło
3
Wielkie dzięki! Aby wygenerować klasy najwyższego poziomu zamiast hermetyzowanych, zobacz: stackoverflow.com/questions/13175224/… . A jeśli prowadzi to do konfliktów nazw klas, zobacz: stackoverflow.com/questions/13414407/…
jutro
38

Jeśli chcesz rozpocząć kodowanie Java do XML i XML do Java w mniej niż 5 minut, wypróbuj Simple XML Serialization. Nie trać godzin na naukę interfejsu API JAXB http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php

Jeśli jednak naprawdę chcesz nauczyć się JAXB, oto doskonały samouczek http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml

Zawartość poradnika:

JAXB do prostej serializacji Java-XML

Istnieje wiele sposobów serializacji XML w Javie. Jeśli chcesz dokładniejszej kontroli nad analizowaniem i serializacją, możesz wybrać SAX, DOM lub Stax, aby uzyskać lepszą wydajność. Jednak to, co często chcę robić, to proste mapowanie między POJO i XML. Jednak tworzenie klas Java do ręcznego analizowania zdarzeń XML nie jest trywialne. Niedawno odkryłem, że JAXB to szybkie i wygodne mapowanie lub serializacja Java-XML.

JAXB zawiera wiele przydatnych funkcji, możesz sprawdzić implementację referencyjną tutaj. Blog Kohsuke jest również dobrym źródłem informacji o JAXB. W tym wpisie na blogu pokażę, jak wykonać prostą serializację Java-XML za pomocą JAXB.

POJO do XML

Powiedzmy, że mam obiekt Java Item. Chcę serializować obiekt Item do formatu XML. Najpierw muszę dodać do tego POJO kilka adnotacji XML z pakietu javax.xml.bind.annotation. *. Zobacz listę kodu 1 dla Item.java

Z kodu

  • @XmlRootElement(name="Item") wskazuje, że chcę być elementem głównym.
  • @XmlType(propOrder = {"name", "price"}) wskazuje kolejność, w jakiej chcę, aby element był ułożony w danych wyjściowych XML.
  • @XmlAttribute(name="id", ...) wskazuje, że id jest atrybutem elementu głównego.
  • @XmlElement(....) wskazuje, że chcę, aby cena i nazwa były elementem elementu.

Mój Item.javajest gotowy. Mogę wtedy przejść dalej i utworzyć skrypt JAXB do organizowania elementu.

//creating Item data object
Item item = new Item();
item.setId(2);
item.setName("Foo");
item.setPrice(200);
.....

JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
//I want to save the output file to item.xml
marshaller.marshal(item, new FileWriter("item.xml"));

Aby uzyskać pełną listę kodów, zobacz Listing 2 main.java. Powstaje item.xmlplik wyjściowy z listą kodów 3 . To wygląda tak:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">

 <ns1:itemName>Foo</ns1:itemName>
<ns1:price>200</ns1:price>

</ns1:item>

Łatwe, prawda? Możesz alternatywnie skierować wyjściowy kod XML jako tekst String, Stream, Writer, ContentHandler itp., Po prostu zmieniając parametr metody marshal (...), takiej jak

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
// save xml output to the OutputStream instance
marshaller.marshal(item, <java.io.OutputStream instance>);

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
//save to StringWriter, you can then call sw.toString() to get java.lang.String
marshaller.marshal(item, sw);

XML do POJO

Odwróćmy ten proces. Załóżmy, że mam teraz fragment danych ciągu XML i chcę przekształcić go w obiekt Item.java. Wyglądają jak dane XML (lista kodu 3)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">
<ns1:itemName>Bar</ns1:itemName>
<ns1:price>80</ns1:price>
</ns1:item>

Następnie mogę cofnąć ten kod XML do obiektu Item przez

...
ByteArrayInputStream xmlContentBytes = new ByteArrayInputStream (xmlContent.getBytes());
JAXBContext context = JAXBContext.newInstance(Item.getClass());
Unmarshaller unmarshaller = context.createUnmarshaller();
//note: setting schema to null will turn validator off
unmarshaller.setSchema(null);
Object xmlObject = Item.getClass().cast(unmarshaller.unmarshal(xmlContentBytes));
return xmlObject;
...

Pełną listę kodów można znaleźć na liście kodów 2 (main.java). Źródło XML może przybierać różne formy, zarówno ze strumienia, jak iz pliku. Jedyną różnicą jest ponownie parametr metody:

...
unmarshaller.unmarshal(new File("Item.xml")); // reading from file
...
// inputStream is an instance of java.io.InputStream, reading from stream
unmarshaller.unmarshal(inputStream);

Walidacja za pomocą schematu XML

Ostatnią rzeczą, o której chcę tutaj wspomnieć, jest walidacja wejściowego XML ze schematem przed cofnięciem korekty do obiektu Java. Tworzę plik schematu XML o nazwie item.xsd. Aby uzyskać pełną listę kodów, zobacz Listing 4 (Item.xsd). Teraz muszę zarejestrować ten schemat do walidacji.

...
Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(new File("Item.xsd"));
unmarshaller.setSchema(schema); //register item.xsd shcema for validation
...

Kiedy próbuję odszukać dane XML do POJO, jeśli wejściowy XML nie jest zgodny ze schematem, zostanie przechwycony wyjątek. Aby uzyskać pełną listę kodów, zobacz Listing 5 (invalid_item.xml).

javax.xml.bind.UnmarshalException
- with linked exception:
javax.xml.bind.JAXBException caught: null
[org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'item1' is
                                not a valid value for 'integer'.]

Tutaj zmieniam atrybut „id” na ciąg znaków zamiast liczby całkowitej.

Jeśli dane wejściowe XML są zgodne ze schematem, dane XML zostaną pomyślnie cofnięte do obiektu Item.java.

Baran McRae
źródło
1
Wygląda to bardzo obiecująco i jest dużo prostsze i przyjemniejsze w pracy z tym, do czego go potrzebuję, niż coś dużego i skomplikowanego, takiego jak JAXB. Niestety, nie widzę żadnego sposobu na przekonwertowanie moich istniejących plików .XSD do .class, od czego naprawdę muszę zacząć. Czy jest na to sposób?
Keith Palmer Jr.
7
Niestety blog z samouczkiem JAXB jest niedostępny.
Luis C.
możemy to łatwo zrobić za pomocą wtyczki jaxb2-maven, sprawdź ten samouczek journaldev.com/1312/ ...
Pankaj
co jest skomplikowanego w ""% java_home% \ bin \ xjc "-p [twoja przestrzeń nazw] [xsd_file] .xsd"?
gorefest
30

Korzystanie z Eclipse IDE: -

  1. skopiuj xsd do nowego / istniejącego projektu.
  2. Upewnij się, że w ścieżce klas znajdują się pliki JAR wymagane przez JAXB. Możesz go pobrać tutaj .
  3. Kliknij prawym przyciskiem myszy plik XSD -> Generuj -> Klasy JAXB.
Kumar Sambhav
źródło
17

najłatwiej jest użyć wiersza poleceń. Po prostu wpisz katalog swojego pliku .xsd:

xjc myFile.xsd.

Więc java wygeneruje wszystkie Pojos.

Crozeta
źródło
14

Do tego celu można użyć Mavena, musisz dodać zależności i po prostu wyczyścić aplikację. Otrzymasz wszystkie klasy utworzone automatycznie w folderze docelowym.

Po prostu skopiuj je z miejsca docelowego do żądanego miejsca, oto pom.xml, którego użyłem do stworzenia sklasyfikowanych z plików xsd:

    <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>jaxb2-maven-plugin</artifactId>

     <executions>
      <execution>
       <goals>
        <goal>xjc</goal>
       </goals>
      </execution>
     </executions>
     <configuration>
      <schemaDirectory>src/main/webapp/schemas/</schemaDirectory>
     </configuration>
    </plugin>

   </plugins>
  </pluginManagement>
 </build>
</project>

Po prostu umieść swoje pliki xsd w "src / main / webapp / schemas /", a maven znajdzie je w czasie kompilacji.

Mam nadzieję, że to Ci pomoże. Więcej informacji można znaleźć pod adresem http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html

Mam nadzieję, że to pomoże :)

neel4soft
źródło
1
Czy to faktycznie działa z katalogiem zasobów? (src / main / resources / schemas), bo ciągle dostaję to:No XSD files found. Please check your plugin configuration.
zygimantus
7

Cóż, najlepszą opcją jest %java_home%\bin\xjc -p [your namespace] [xsd_file].xsd.

Mam też pytanie, czy mamy tutaj możliwość wykonania inżynierii odwrotnej. jeśli tak, czy możemy wygenerować xsd z klasy pojo?

sree
źródło
xjc jest dostępny tylko w java6
sree
7

Jeśli nie masz nic przeciwko korzystaniu z zewnętrznej biblioteki, używałem do tego Castor w przeszłości.

Marc Novakowski
źródło
Jeśli generujesz kod za pomocą Castor, czy te wygenerowane klasy nadal zależą od Caster po fakcie? A może mógłbym przenieść te klasy na maszynę bez bibliotek Castor, a one nadal by działały?
Keith Palmer Jr.
Nie, wygenerowane klasy nie są zależne od bibliotek Castor.
dave
Czy są jakieś dobre samouczki na temat korzystania z Castor w tym celu? Wygląda bardzo obiecująco ... ale Java nie jest co najmniej moim najsilniejszym językiem. Nie jestem pewien, jakie pliki / pakiety Castor muszę pobrać i jak właściwie generować kod ... jakieś przykłady dla początkujących krok po kroku?
Keith Palmer Jr.
Sprawdź tę stronę, aby uzyskać dokumentację dotyczącą korzystania z klasy Castor SourceGenerator: castor.org/sourcegen.html
Marc Novakowski
2
Wygląda na to, że kółko od dawna nie żyje ... Wszystkie linki do dokumentów to 404.
Paweł Veselov
5

Ograniczenie JAXB.

Pracowałem nad JAXB, moim zdaniem jest to niezły sposób radzenia sobie z danymi pomiędzy obiektami XML i Java. Pozytywne strony to sprawdzona i lepsza wydajność i kontrola nad danymi w czasie wykonywania. Przy dobrym wykorzystaniu wbudowanych narzędzi lub skryptów zajmie to dużo pracy związanej z kodowaniem.

Odkryłem, że część konfiguracyjna nie jest od razu zadaniem i spędziłem godziny na przygotowywaniu konfiguracji środowiska programistycznego.

Jednak porzuciłem to rozwiązanie z powodu głupiego ograniczenia, z którym się spotkałem. Moja definicja schematu XML (XSD) ma atrybut / element o nazwie „wartość” i muszę używać XSD w obecnej postaci. To bardzo małe ograniczenie zmusiło mój krok wiązania XJC nie powiódł się z błędem „Wartość właściwości” już użyta. "

Wynika to z implementacji JAXB, proces wiązania próbuje utworzyć obiekty Java z XSD, dodając kilka atrybutów do każdej klasy, a jeden z nich jest atrybutem wartości. Podczas przetwarzania mojego XSD skarżył się, że istnieje już właściwość o tej nazwie.

Baran
źródło
4

Czy XJC JAXB nie jest możliwą odpowiedzią na to? Próbuję osiągnąć to samo. Jednak wciąż w fazie „próbowania”. Przeszedłem przez XJC, więc pomyśl o udostępnieniu.

Niks
źródło
2

Dobrze znany JAXB

Istnieje wtyczka maven która może zrobić to za Ciebie na dowolnym etapie kompilacji.

Możesz to zrobić na dwa sposoby: xsd <-> Java

François Wauquier
źródło