Jaxb (XJC) gerando classes do XML Schema (XSD) com descrições de classe e campo como anotações. Plug-in XJC

Eu acho que muitos desenvolvedores de Java que pelo menos uma vez encontraram Web- usaram a geração de classes Java DTO , conforme descrito pelo XML Schema ( XSD ) . O Jaxb lida com isso com um estrondo, não importa como usá-lo, por meio de xjc ou wsimport partir da linha de comando, plugins maven ou gradle.


É tão rápido e fácil gerar classes a partir de um esquema XSD . Mas aqui está um problema - as descrições disponíveis no circuito original desaparecem quase completamente!


Na prática , como apenas a própria classe terá uma descrição Javadoc , em um formato fixo (onde você não pode separar a descrição e o fragmento XML sem os regulares, por exemplo), a descrição dos campos (campos) está completamente ausente. E se você, como eu, precisa deles também em tempo de execução ( runtime ), então há problemas .


Por mais estranho que pareça, foi necessário superar isso, a tarefa levou muito tempo e, como resultado, escrevi um plug-in, que gostaria de apresentar na esperança de que ele possa salvar algumas pessoas algumas horas no futuro.


Visão geral dos recursos da Jaxb


O Jaxb tem uma longa história e uma boa descrição oficial, incluindo a adição de comportamento às classes geradas.


A principal ferramenta para chamar a geração de classe a partir da linha de comando - xjc também não possui o menor número de chaves. No entanto, nenhum deles é para o nosso caso.


Obviamente, você não pode deixar de mencionar -b , onde pode fornecer sua própria ligação. E essa é uma arma muito poderosa, especialmente em conjunto com vários plug-ins. Um post muito bom (em inglês) - eu recomendo a leitura como uma breve introdução. Mas a ligação é, na maioria das vezes, limitada aos valores estáticos das anthotations atribuídas ou dos nomes dados, indicando os elementos aos quais é aplicada. No meu problema, isso não ajuda.


Plug-ins Jaxb (XJC)


Enquanto procurava uma solução pronta, encontrei muitos plugins que expandem a geração. Suponho que a revisão deles esteja além do escopo deste post. O que é importante, não encontro o que está fazendo exatamente o que preciso.


Porém, ao ler as respostas e as perguntas em http://stackoverflow.com/ , encontrei várias perguntas desse tipo, por exemplo:


  1. Usando JAXB para manipular anotações de esquema .
  2. Como fazer com que as classes geradas contenham Javadoc da documentação do esquema XML
  3. Como posso gerar uma classe a partir da qual posso recuperar o XML de um nó como uma String

e nenhuma resposta completa em alguns anos!


Mas, voltando ao tópico das oportunidades, verificou-se que existe uma API para escrever plugins! Baixo nível, às vezes confuso, quase sem documentação ... Mas posso dizer que isso é muito avançado, ou seja, é possível intervir muito diretamente em quais processos. A propósito, as respostas a ele são frequentemente referidas, para muitos casos não padronizados. Bem, eu tentei escrever um plugin.


Para aqueles que estão interessados ​​nos detalhes do processo de escrever seus plugins, posso recomendar artigos:



O que eu queria e por que


Para uma de nossas integrações, o cliente forneceu um arquivo com arquivos XSD , segundo os quais tivemos que gerar um modelo no MDM Unidata , com o qual trabalhamos, para configurar ainda mais as regras de qualidade.


Observo que o próprio sistema MDM é proprietário, é improvável que muitos estejam familiarizados com ele, mas isso realmente não importa. A conclusão é que tivemos que criar diretórios e registros a partir de descrições XSD . Ao mesmo tempo, os registros têm campos que usam um identificador (nome do campo) e um "nome para exibição" - um nome que é compreensível para uma pessoa em russo. Uma analogia simples pode ser desenhada (e este provavelmente também é um exemplo útil para aplicação) com um RDBMS em termos dos quais podemos assumir que queríamos criar tabelas de banco de dados, mas ao mesmo tempo fornecer descrições ( comment ) para cada coluna para uso posterior.

Meu plano era este:


  1. Gerando Classes XSD Usando XJC
  2. Depois, pegamos uma bela biblioteca de reflexões e iteramos sobre todos os objetos, percorrendo recursivamente os campos.

Tudo rapidamente funcionou para nomes latinos, retirados das aulas de field . Mas a descrição russa, legível por humanos, não estava em lugar nenhum!


A edição manual de descrições não é uma opção, pois existem dezenas de milhares de campos aninhados.


A primeira tentativa foi escrever um analisador semelhante no Groovy , rasgando as descrições do XSD . E, em geral, foi implementado. Mas rapidamente ficou claro que há muitos casos em que é necessário processamento adicional - chamadas recursivas, suporte para extensões XSD 1.1 na forma de restriction / extension (com suporte a herança e substituição), diferentes tipos dos quais geram campos de classe como <element> e <attribute> , <sequence> , <choose> e muitas outras pequenas coisas. A implementação estava cheia de adições, mas ela não aumentou a harmonia.


Como resultado, voltei à ideia de escrever o plug-in xjc-documentation-annotation-plugin , que apresento a você, na esperança de que seja útil para alguém, exceto eu!


xjc-documentation-annotation-plugin


Tudo está definido no github: https://github.com/Hubbitus/xjc-documentation-annotation-plugin
Existem instruções, testes e um - gradle separado - gradle com um exemplo de uso.


Eu acho que não faz sentido copiar a descrição aqui de lá, apenas mostrar brevemente o que ela faz.


Digamos que exista um fragmento XSD :


  <xs:complexType name="Customer"> <xs:annotation> <xs:documentation></xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="name" type="xs:string"> <xs:annotation> <xs:documentation>  </xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> 

Por padrão, o XJC gerar uma classe de XJC partir dela (getters, setters e alguns detalhes irrelevantes são omitidos para facilitar a leitura):


 /** *  * * <p>Java class for Customer complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * &lt;complexType name="Customer"&gt; * &lt;complexContent&gt; * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt; * &lt;sequence&gt; * &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/&gt; * &lt;element name="age" type="{http://www.w3.org/2001/XMLSchema}positiveInteger"/&gt; * &lt;/sequence&gt; * &lt;/restriction&gt; * &lt;/complexContent&gt; * &lt;/complexType&gt; * </pre> * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Customer", propOrder = { "name", "age" }) public class Customer { @XmlElement(required = true) protected String name; @XmlElement(required = true) @XmlSchemaType(name = "positiveInteger") protected BigInteger age; } 

Com o plug-in, você obtém (o Javadoc permanece o mesmo, omitido por simplicidade):


 @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Customer", propOrder = { "name", "age" }) @XsdInfo(name = "", xsdElementPart = "<complexType name=\"Customer\">\n <complexContent>\n <restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n <sequence>\n <element name=\"name\" type=\"{http://www.w3.org/2001/XMLSchema}string\"/>\n <element name=\"age\" type=\"{http://www.w3.org/2001/XMLSchema}positiveInteger\"/>\n </sequence>\n </restriction>\n </complexContent>\n</complexType>") public class Customer { @XmlElement(required = true) @XsdInfo(name = "  ") protected String name; @XmlElement(required = true) @XmlSchemaType(name = "positiveInteger") @XsdInfo(name = "") protected BigInteger age; } 

Confira as anotações adicionadas ao @XmlType .


Usar isso é tão simples quanto qualquer outra anotação:


  XsdInfo xsdAnnotation = CadastralBlock.class.getDeclaredAnnotation(XsdInfo.class); System.out.println("XSD description: " + xsdAnnotation.name()); 

Um exemplo de trabalho está nos testes: 1 , 2 .

Source: https://habr.com/ru/post/pt437914/


All Articles