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:
- Usando JAXB para manipular anotações de esquema .
- Como fazer com que as classes geradas contenham Javadoc da documentação do esquema XML
- 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:
- Gerando Classes
XSD
Usando XJC
- 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):
@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 .