Gerar classes Java a partir de arquivos .XSD ...?

127

Eu tenho um arquivo de esquema .XSD gigantesco do QuickBooks SDK que define solicitações / respostas XML que posso enviar / receber do QuickBooks.

Eu gostaria de poder gerar facilmente classes Java a partir desses arquivos .XSD, que eu poderia usar para organizar XML para objetos Java e objetos Java para XML.

Existe uma maneira fácil de fazer isso ...?

Idealmente, não exigiria nenhuma biblioteca externa à distribuição Java básica em tempo de execução. Mas eu sou flexível ...

Keith Palmer Jr.
fonte
6
Se você quiser geração Manual, coloque o arquivo .xsd em seu projeto eclipse, clique direito no arquivo, depois clique em "gerar"
Junchen Liu

Respostas:

121

JAXB faz exatamente o que você deseja. Ele está embutido no JRE / JDK a partir de 1.6

basszero
fonte
7
Infelizmente, essa funcionalidade não estará mais disponível a partir do Java 9. Isso ocorre porque as classes envolvidas (em particular, as classes com.sun.tools.xjc. *) Não estarão mais disponíveis através do JDK.
Marco
4
Não acho que a remoção disso do JDK deva ser um problema, porque o projeto java.net (vinculado na resposta) provavelmente permanecerá.
Stmoebius 14/09/16
1
Conforme explicado aqui , você pode adicionar as dependências no Java 9 por um argumento de linha de comando ou adicionar a dependência manualmente.
Matthias Ronge
118

Para expandir os comentários "use JAXB" acima,

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

por exemplo, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

Espere um pouco, e se você tivesse um arquivo XSD bem formado, obterá algumas classes Java bem formadas

Ed Norris
fonte
3
Ótimo, obrigado! Para gerar classes de nível superior em vez de encapsuladas, consulte: stackoverflow.com/questions/13175224/… . E se isso levar a conflitos de nome de classe, consulte: stackoverflow.com/questions/13414407/…
amanhã
38

Se você deseja começar a codificar Java para XML e XML para Java em menos de 5 minutos, tente Serialização Simples de XML. Não gaste horas aprendendo a API JAXB http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php

No entanto, se você está realmente interessado em aprender JAXB, aqui está um excelente tutorial http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml

Conteúdo do tutorial:

JAXB para serialização Java-XML simples

Existem várias maneiras de serializar XML em Java. Se você deseja controle refinado sobre análise e serialização, pode optar por SAX, DOM ou Stax para obter melhor desempenho. No entanto, o que geralmente quero fazer é um mapeamento simples entre POJOs e XML. No entanto, a criação de classes Java para fazer a análise de eventos XML manualmente não é trivial. Recentemente, descobri que o JAXB é um mapeamento ou serialização Java-XML rápido e conveniente.

O JAXB contém muitos recursos úteis, você pode conferir a implementação de referência aqui. O Blog de Kohsuke também é um bom recurso para aprender mais sobre o JAXB. Para esta entrada do blog, mostrarei como fazer uma serialização Java-XML simples com JAXB.

POJO para XML

Digamos que eu tenho um objeto Java de item. Eu quero serializar um objeto Item para o formato XML. O que preciso fazer primeiro é anotar este POJO com algumas anotações XML do pacote javax.xml.bind.annotation. *. Veja a listagem de códigos 1 para Item.java

Do código

  • @XmlRootElement(name="Item") indica que eu quero ser o elemento raiz.
  • @XmlType(propOrder = {"name", "price"}) indica a ordem em que desejo que o elemento seja organizado na saída XML.
  • @XmlAttribute(name="id", ...) indica que id é um atributo para o elemento raiz.
  • @XmlElement(....) indica que eu quero que preço e nome sejam elemento dentro de Item.

Meu Item.javaestá pronto. Posso então criar um script JAXB para empacotar Item.

//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"));

Para obter a listagem completa de códigos, consulte a Listagem de código 2 main.java. O item.xmlarquivo de saída da Listagem de Código 3 é criado. Se parece com isso:

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

Fácil né? Como alternativa, você pode canalizar o XML de saída como texto String, Stream, Writer, ContentHandler, etc, simplesmente alterando o parâmetro do método marshal (...) como

...
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 para POJO

Vamos reverter o processo. Suponha que agora eu tenho um pedaço de dados da seqüência XML e desejo transformá-lo no objeto Item.java. Os dados XML (listagem de código 3) parecem

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

Em seguida, posso desselecionar esse código xml para o objeto Item

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

Para obter uma listagem completa de códigos, consulte a Listagem de código 2 (main.java). A fonte XML pode vir de várias formas, tanto do Stream quanto do arquivo. A única diferença, novamente, é o parâmetro do método:

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

Validação com esquema XML

A última coisa que quero mencionar aqui é a validação do XML de entrada com o esquema antes de desmontar o objeto Java. Eu crio um arquivo de esquema XML chamado item.xsd. Para obter uma listagem completa de códigos, consulte a Listagem de código 4 (Item.xsd). Agora, o que tenho que fazer é registrar esse esquema para validação.

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

Quando tento desselecionar dados XML para POJO, se o XML de entrada não estiver em conformidade com o esquema, a exceção será capturada. Para obter uma listagem completa de códigos, consulte a Listagem de código 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'.]

Aqui eu altero o atributo 'id' para string em vez de inteiro.

Se a entrada XML for válida no esquema, os dados XML serão desassociados para o objeto Item.java com êxito.

Aries McRae
fonte
1
Isso parece muito promissor, e muito mais simples e agradável de trabalhar para o que eu preciso, do que algo grande e complicado como o JAXB. Infelizmente, não vejo nenhuma maneira de converter meus arquivos .XSD em .class existentes, que é realmente o que preciso iniciar. Existe uma maneira de fazer isso?
Keith Palmer Jr.
7
Infelizmente, o blog com o Tutorial JAXB está offline.
Luis C.
podemos fazê-lo facilmente usando o jaxb2-maven-plugin, verifique este tutorial journaldev.com/1312/…
Pankaj
o que é complicado sobre ""% java_home% \ bin \ xjc "-p [seu espaço para nome] [xsd_file] .xsd"?
Gorefest
30

Usando o Eclipse IDE: -

  1. copie o xsd em um projeto novo / existente.
  2. Certifique-se de ter os JARs requeridos pelo JAXB em seu caminho de classe. Você pode baixar um aqui .
  3. Clique com o botão direito do mouse no arquivo XSD -> Gerar -> classes JAXB.
Kumar Sambhav
fonte
17

a maneira mais fácil é usar a linha de comando. Basta digitar o diretório do seu arquivo .xsd:

xjc myFile.xsd.

Portanto, o java irá gerar todos os Pojos.

Crozeta
fonte
14

Maven pode ser usado para esse fim, você precisa adicionar algumas dependências e apenas limpar seu aplicativo. Você receberá todas as classes criadas automaticamente na sua pasta de destino.

Basta copiá-los do destino para o local desejado, aqui está o pom.xml que eu usei para criar os arquivos xsd classificados:

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

Coloque seus arquivos xsd em "src / main / webapp / schemas /" e o maven os encontrará em tempo de compilação.

Espero que isso ajude você. Mais informações podem ser encontradas em http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html

Espero que ajude :)

neel4soft
fonte
1
Isso realmente funciona com o diretório de recursos? (src / main / resources / schemas), porque eu continuo recebendo esta:No XSD files found. Please check your plugin configuration.
zygimantus
7

Bem, a melhor opção é %java_home%\bin\xjc -p [your namespace] [xsd_file].xsd .

Também tenho uma dúvida se temos a opção de fazer engenharia reversa aqui. se sim, podemos gerar xsd a partir da classe pojo?

sree
fonte
xjc está disponível apenas em java6
sree
7

Se você não se importa em usar uma biblioteca externa, usei o Castor para fazer isso no passado.

Marc Novakowski
fonte
Se você gerar código com o Castor, essas classes geradas ainda dependem do Caster após o fato? Ou eu poderia mover essas classes para uma máquina sem as bibliotecas do Castor, e elas ainda funcionariam?
Keith Palmer Jr.
Não, as classes geradas não dependem das bibliotecas do Castor.
dave
Existem bons tutoriais sobre como usar o Castor para fazer isso? Parece muito promissor ... mas Java é, para dizer o mínimo, não é a minha linguagem mais forte. Não sei ao certo quais arquivos / pacotes do Castor preciso baixar e como realmente gerar o código ... algum exemplo passo a passo para iniciantes?
Keith Palmer Jr.
Confira esta página para obter documentação sobre como usar a classe Castor SourceGenerator: castor.org/sourcegen.html
Marc Novakowski
2
Parece que rícino é morto há muito tempo ... ligações Docs são todos 404.
Pawel Veselov
5

Limitação JAXB.

Eu trabalhei no JAXB, pois, na minha opinião, é uma boa maneira de lidar com dados entre objetos XML e Java. Os lados positivos são comprovados e têm melhor desempenho e controle sobre os dados durante o tempo de execução. Com um bom uso de ferramentas ou scripts criados, isso tira muitos esforços de codificação.

Achei que a parte da configuração não é uma tarefa imediata e gastei horas na instalação do ambiente de desenvolvimento.

No entanto, deixei cair esta solução devido a uma limitação boba que enfrentei. Minha definição de esquema XML (XSD) tem um atributo / elemento com o nome "valor" e eu tenho que usar o XSD como está. Essa restrição muito pequena forçou a etapa de ligação minha XJC falhou com um erro "Propriedade 'Valor' já usado".

Isso ocorre devido à implementação do JAXB, o processo de ligação tenta criar objetos Java a partir do XSD, incluindo poucos atributos em cada classe e um deles sendo um atributo de valor. Quando processou meu XSD, ele reclamou que já havia uma propriedade com esse nome.

RAM
fonte
4

O XJC de JAXB não é uma resposta possível para isso? Estou tentando conseguir a mesma coisa. Ainda na fase "difícil". Me deparei com o XJC, então pensei em compartilhar.

Niks
fonte
2

O conhecido JAXB

Existe um plug-in do maven que pode fazer isso por você em qualquer fase de criação que você desejar.

Você poderia fazer isso de duas maneiras: xsd <-> Java

François Wauquier
fonte
1

Falando sobre a limitação do JAXB, uma solução ao ter o mesmo nome para diferentes atributos está incluindo personalizações jaxb embutidas no xsd:

+

. . declarações vinculativas. .

ou personalizações externas ...

Você pode ver mais informações em: http://jaxb.java.net/tutorial/section_5_3-Overriding-Names.html

Nady
fonte