JAXB Annotate Home - highsource/jaxb-tools GitHub Wiki
Annotate plugins is capable of adding arbitrary annotations to the generated sources.
Annotate plugin uses JAXB Annox to read annotations from binding customizations and adds them to the schema-derived classes. Here's a small example:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.1"
xmlns:annox="http://annox.dev.java.net"
jaxb:extensionBindingPrefixes="annox"
xmlns:jl="http://annox.dev.java.net/java.lang">
<xsd:element name="foo" type="FooType"/>
<xsd:complexType name="FooType">
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>
<jl:SuppressWarnings/>
</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="bar" type="xsd:string"/>
<xsd:element name="foobar" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>
<jl:SuppressWarnings/>
</annox:annotate>
<annox:annotate target="setter">
<jl:Deprecated/>
</annox:annotate>
<annox:annotate target="setter-parameter">
<jl:Deprecated/>
</annox:annotate>
<annox:annotate target="getter">
<jl:Deprecated/>
</annox:annotate>
<annox:annotate target="field">
<jl:Deprecated/>
</annox:annotate>
<annox:annotate target="class">
<jl:Deprecated/>
</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Check Annox user guide for information on how to define Java annotations in XML form.
Below is the generated code:
package generated;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "FooType", propOrder = {
"bar",
"foobar"
})
@SuppressWarnings({
})
@Deprecated
public class FooType {
@XmlElement(required = true)
protected String bar;
@XmlElement(required = true)
@Deprecated
protected String foobar;
public String getBar() {
return bar;
}
public void setBar(String value) {
this.bar = value;
}
@Deprecated
public String getFoobar() {
return foobar;
}
@SuppressWarnings({
})
@Deprecated
public void setFoobar(
@Deprecated
String value) {
this.foobar = value;
}
}
Please see this test project for example.
The plugin is activated by the -Xannotate
command-line argument.
The purpose of the Annotate Plugin is to allow adding arbitrary annotations to the classes generated by the schema compiler (XJC). When schema is compiled, the Annotate Plugin reads annotation definitions from schema bindings and adds appropriate code to the generated classes.
In order to use this plugin to add your own annotations to the generated classes you have to do two things :
- Activate the plugin.
- Add definitions of annotations you want to add to schema bindings.
First part is trivial. Second part - defining your annotations in schema bindings can be a bit more tricky. It is explained in the next sections.
Schema bindings are essentially XML documents which provide XJC with additional information which may be used to customize schema compilation. There is a number of standard JAXB customization elements (like jaxb:class
or jaxb:property
), but XJC also allows vendor customizations. Annotate Plugin employs this possibility and uses customization elements as a source for definitions of annotations. Annotations are defined XML elements; Annotate plugin uses Annox to read annotations from XML definitions.
Check Annox user guide for detailed information on how to define Java annotations in XML form.
There are mainly two ways to add bindings to your schema: directly in schema files or in external binding files. You can add annotation definitions in both cases, but due to certain technical reasons there are slight differences between these two variants. I'll demonstrate it on an example of org.hibernate.search.annotations.FieldBridge
from Hibernate Search.
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.1"
xmlns:annox="http://annox.dev.java.net"
xmlns:hs="http://annox.dev.java.net/org.hibernate.search.annotations"
jaxb:extensionBindingPrefixes="annox">
...
<xsd:complexType ...>
<xsd:sequence>
....
<xsd:element name="name" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>
<hs:FieldBridge impl="com.acme.foo.MyFieldBridge">
<params>
<hs:Parameter name="foo" value="bar"/>
</params>
</hs:FieldBridge>
</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
....
</xsd:sequence>
....
</xsd:complexType>
...
</xsd:schema>
Produces:
@FieldBridge(impl = com.acme.foo.MyFieldBridge.class, params = {
@Parameter(name = "foo", value = "bar")
})
Note the annox:annotate
element within schema - it is the customization element that the Annotate Plugin processes. The hs:FieldBridge
sub-element is the XML: definition of the @FieldBridge
annotation.
The key to the elegant definition in the example above is the http://annox.dev.java.net/org.hibernate.search.annotations
associated with the hs prefix. Namespace URI points to the org.hibernate.search.annotations
package - this is how the Annotate Plugin (i.e. the underlying Annox parser) knows that hs:FieldBridge
is actually @org.hibernate.search.annotations.FieldBridge
Java class.
Unfortunatelly the elegant syntax above does not work when defining customization elements in external binding files. XJC is for some reason too strict here. It considers the package namespace URI (like http://annox.dev.java.net/org.hibernate.search.annotations
above) to be a vendor extension URI and consequently fails. I believe this to be a bug in XJC.
Accordignly, we can't use package namespaces in external binding files. All the binding definitions must be declared in a single namespace. Here's how binding.xjb
binding file looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
version="2.1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
jaxb:extensionBindingPrefixes="annox">
<jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
...
<jaxb:bindings node="xs:complexType[@name='...']/xs:sequence/xs:element[@name='name']">
<annox:annotate>
<annox:annotate
annox:class="org.hibernate.search.annotations.FieldBridge"
impl="com.acme.foo.MyFieldBridge">
<annox:annotate annox:field="params">
<annox:annotate annox:class="org.hibernate.search.annotations.Parameter"
name="foo"
value="bar"/>
</annox:annotate>
</annox:annotate>
</annox:annotate>
</jaxb:bindings>
...
</jaxb:bindings>
</jaxb:bindings>
In this case we had to use annox:annotate
elements everywhere. The annox:class
attribute is used to provide the class name of the annotation. In case of nested annotation definitions annox:field
indicates the field of the annotation.
You can use annox:annotateClass
, annox:annotateProperty
, annox:annotateEnum
, annox:annotateEnumConstant
, annox:annotateElement
, annox:annotate/@target="setter-parameter"
if you want your customization to be a bit more specific.
If an annotation of the given class already exists, this annotation will be augmented. Thus, the following customizations:
<annox:annotate target="class">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="someElement"/>
</annox:annotate>
<annox:annotate target="class">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" namespace="someNamespace"/>
</annox:annotate>
Would result in:
@XmlRootElement(name = "someElement", namespace = "someNamespace")