📜 ⬆️ ⬇️

Jaxb (XJC) generates classes from XML Schema (XSD) with annotation class and field descriptions. Xjc plugin

I think many Java-developers who at least once came across Web-сервисами , used generation of Java DTO classes according to the description of XML Schema ( XSD ) . Jaxb copes with this with a bang, no matter how to use it, via xjc or wsimport command line call, maven or gradle plugins.


It is so quick and easy to generate classes from an XSD schema. But here is one problem - the descriptions in the source diagram are almost completely lost!


Practically , because Javadoc will only have a description of the class itself, in a fixed format (where we can’t separate the description and the XML fragment without regulars, for example), the description of the fields (fields) is completely missing. And if you need them, like me, you also need them at runtime ( runtime ) - this is a real disaster .


It was with this that I had to fight, oddly enough, the task took a lot of time, and as a result I wrote a plugin, which I would like to present in the hope that he could save someone a few hours in the future.


Jaxb features overview


Jaxb has a great history and a good official description, including the addition of behavior to the generated classes.


The main tool for invoking class generation from the command line - xjc also has not the smallest number of keys. But none of them, not for our case.


Of course, one can not fail to mention about -b , where you can provide your own binding. And this is a very powerful weapon, especially in conjunction with multiple plug-ins. Very good blog post (in English) - I recommend reading as a brief introduction. But the binding is mostly limited to the static values ​​of the assigned annotations or given names, indicating the elements to which it is applied. It doesn't help my problem.


Jaxb (XJC) plugins


While looking for a ready-made solution, I found many plug-ins that extend generation. I believe their review is beyond the scope of this post. What is important, doing what is necessary to me, I have not found.


But then, while reading the answers and questions at http://stackoverflow.com/ , I found several questions of this kind, for example:


  1. Using JAXB to handle schema annotations .
  2. How to make generated classes contain Javadoc from XML Schema documentation
  3. How can I generate a XML from a node as a String

and no complete answer, some over many years!


But, returning to the topic of possibilities, it turned out that there is an API for writing plugins! Low-level, sometimes confusing, almost without documentation ... But I can say this is very advanced, that is, you can directly intervene in many processes. By the way, the responses to it are often referenced, for many non-standard cases. So I tried to write a plugin.


For those who are interested in the details of the process of writing their plug-ins, I can recommend articles:



What you wanted and why


For one of our integrations, the customer provided an archive with XSD files, according to which we had to generate a model in Unidata MDM , with which we work, to further adjust the quality rules.


I note that the MDM system itself is proprietary, it is unlikely that many are familiar with it, but this does not really matter. The bottom line is that we had to create reference books and registers for XSD descriptions. At the same time, the registries have fields in which both the identifier (the name of the field) and the "display name" are used - the name that the person understands is in Russian. A simple analogy can be drawn (and this is probably also a useful example for use) with RDBMS in terms of which we can assume that we wanted to make database tables, but at the same time give descriptions ( comment ) for each column for later use.

My plan was this:


  1. Generating XSD Classes with XJC
  2. Then we take an excellent library of reflections and iterate over all objects, recursively descending through the fields.

Everything worked quickly for Latin names that were taken from fields of the field . But the Russian, humane description was nowhere to take!


Manual description is not an option, because there are tens of thousands of nested fields.


The first attempt was to write a similar parser on Groovy yourself, tearing out descriptions from XSD . And in general, it was implemented. But it quickly became clear that there are many cases where additional processing is required - recursive calls, support for XSD 1.1 extensions in the form of a restriction / extension (with support for inheritance and overriding), different types of which generate class fields like <element> and <attribute> , <sequence> , <choose> and many other small things. Realization overgrown with additions, but she was not slim.


As a result, I returned to the idea of ​​writing a plug-in xjc-documentation-annotation-plugin , which I represent to you, in the hope that it will be useful to someone other than me!


xjc-documentation-annotation-plugin


Everything is posted on the githaba: https://github.com/Hubbitus/xjc-documentation-annotation-plugin
There are also instructions, tests and a separate демо-проект для gradle with an example of use.


I think it makes no sense to copy the description here from there, just briefly show you what he does.


Let's say there is such an XSD fragment:


  <xs:complexType name="CadastralBlock"> <xs:annotation> <xs:documentation>Кадастровый квартал</xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="number" type="xs:string"> <xs:annotation> <xs:documentation>Кадастровый номер</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> 

By default, XJC generate a XJC class from it (getters, setters, and some irrelevant details are omitted for readability):


 /** * Кадастровый квартал * * <p>Java class for CadastralBlock complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * &lt;complexType name="CadastralBlock"&gt; * &lt;complexContent&gt; * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt; * &lt;sequence&gt; * &lt;element name="number" type="{http://www.w3.org/2001/XMLSchema}string"/&gt; * &lt;/sequence&gt; * &lt;/restriction&gt; * &lt;/complexContent&gt; * &lt;/complexType&gt; * </pre> * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "CadastralBlock", namespace = "http://hubbitus.info/xjc-plugin-demo", propOrder = { "number" }) public class CadastralBlock { @XmlElement(required = true) protected String number; } 

With the plugin you will get:


 @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "CadastralBlock", namespace = "http://hubbitus.info/xjc-plugin-demo", propOrder = { "number" }) @XsdInfo(name = "Кадастровый квартал", xsdElementPart = "<complexType name=\"CadastralBlock\">\n <complexContent>\n <restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n <sequence>\n <element name=\"number\" type=\"{http://www.w3.org/2001/XMLSchema}string\"/>\n </sequence>\n </restriction>\n </complexContent>\n</complexType>") public class CadastralBlock { @XmlElement(required = true) @XsdInfo(name = "Кадастровый номер") protected String number; } 

Notice the added annotations @XmlType .


Using it is then as simple as any other annotation:


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

A working example is in the tests: 1 , 2 .



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