Jaxb (XJC) class generation 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 the generation of Java
DTO
classes by description XML Schema
( XSD
) . Jaxb copes with this with a bang, it does not matter how to use it, through xjc
either wsimport
a command line call, maven or gradle plugins.
So quickly and easily generate classes from the XSD
schema. But here is one problem - the descriptions in the original scheme are almost completely lost!
Practically , because the Javadoc
description will be only for the class itself, in a fixed format (where we will not separate the description and the fragment XML
without regulars, say), the description of the fields (fields) is completely absent. 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 it is impossible not to mention about -b
where you can provide your 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 specified 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:
- Using JAXB to handle schema annotations .
- How to make generated classes contain Javadoc from XML Schema documentation
- How can I generate a XML from a node as a String
and not a single complete answer, some over many years!
But, returning to the topic of possibilities, it turned out that there is API
for writing plugins! Low-level, sometimes confusing, almost without documentation ... But I can say with this 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:
- Creating an XJC plugin
- How to Implement Your Own XJC Plugin to Generate toString (), equals (), and hashCode () Methods
- StackOverflow has very detailed answers:
What you wanted and why
For one of our integrations, the customer provided an archive with the XSD
files for which we had to generate a model in MDM Unidata , with which we work, to further adjust the quality rules.
I will note that theMDM
system itself is proprietary, it is unlikely that many are familiar with it, but this does not matter much. The bottom line is that we had to createXSD
reference books and registries from the 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:
- We generate classes by
XSD
usingXJC
- 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 ( field
) classes. 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
its own, ripping out descriptions from XSD
. And in general, it was implemented. But it soon became clear that there are many cases which require further processing - recursive calls, support for extensions XSD
1.1 in the form of restriction
/ extension
(with support for inheritance and override), various types of which are generated by a field classes like <element>
and <attribute>
, <sequence>
, <choose>
and many other details. Realization overgrown with additions, but she was not slim.
As a result, I returned to the idea of writing the xjc-documentation-annotation-plugin 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 laid out on the githaba: https://github.com/Hubbitus/xjc-documentation-annotation-plugin
There are also instructions, tests and a separate демо-проект для gradle
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 a XSD
fragment:
<xs:complexTypename="Customer"><xs:annotation><xs:documentation>Пользователь</xs:documentation></xs:annotation><xs:sequence><xs:elementname="name"type="xs:string"><xs:annotation><xs:documentation>Фамилия и имя</xs:documentation></xs:annotation></xs:element></xs:sequence></xs:complexType>
By default, XJC
a class of the type will be generated from it (getters, setters, and some of the irrelevant details are omitted for readability):
/**
* Пользователь
*
* <p>Java class for Customer complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="Customer">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="age" type="{http://www.w3.org/2001/XMLSchema}positiveInteger"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Customer", propOrder = {
"name",
"age"
})
publicclassCustomer{
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
@XmlSchemaType(name = "positiveInteger")
protected BigInteger age;
}
With the plugin, you will receive (it Javadoc
remains the same, omitted for simplicity):
@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>")
publicclassCustomer{
@XmlElement(required = true)
@XsdInfo(name = "Фамилия и имя")
protected String name;
@XmlElement(required = true)
@XmlSchemaType(name = "positiveInteger")
@XsdInfo(name = "Возраст")
protected BigInteger age;
}
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());