I am trying to add a #javax.annotation.Generated annotation to all my classes generated by JAXB from a XSD.
I am using maven-jaxb2-plugin and a binding.xjb file to generate the source. I saw that the JAXB plugin jaxb2-basics-annotate should do the trick. But all I can find are examples that add annotations to specific classes. Like this one:
<jaxb:bindings schemaLocation="csw/2.0.2/CSW-discovery.xsd" node="/xs:schema">
<jaxb:bindings node="xs:complexType[#name='GetRecordsType']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="GetRecordsType" />
</annox:annotate>
</jaxb:bindings>
How can I do this for each of my generated files? Is this possible at all?
It appears you are using highsource/jaxb2-annotate-plugin If you are also using his highsource/maven-jaxb2-plugin, there is builtin support for this feature. Just add this to the plugin configuration:
<configuration>
<markGenerated>true</markGenerated>
</configuration>
Also check controlling the output.
If you are the official jaxb2 plugin, that feature is also builtin
<configuration>
<addGeneratedAnnotation>true</addGeneratedAnnotation>
</configuration>
Related
I use Apache Camel + JAXB for Soap processing. The java glasses are generated by a maven plugin called cxf-codegen-plugin.
The Problem I am facing is that when I want to use a property which is a list. In that case I will always get a list of JAXBElement instead of objects of the correct class.
Assume this given xml snipped:
<domainObjects avqxsi:type="avqsq:AssetAllocation" id="100" name="Some Name">
<nodes>101</nodes>
<nodes>102</nodes>
</domainObjects>
Now all the "nodes" are ids of different domain objects of type AANode. So in the xsd it is defined like so:
<xsd:complexType name="AssetAllocation">
<xsd:complexContent>
<xsd:extension base="avqsq:DomainObject">
<xsd:sequence>
<xsd:element ecore:reference="avqsq:AANode" maxOccurs="unbounded" name="nodes" type="xsd:IDREF"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
And I have defined some bindings.xml:
<jaxb:bindings node="xsd:complexType[#name='AssetAllocation']//xsd:element[#name='nodes']">
<jaxb:property>
<jaxb:baseType name="my.api.xsd.AANode"/>
</jaxb:property>
</jaxb:bindings>
What I want is a POJO property like this:
#XmlElementRef(name = "nodes")
protected List<AANode> nodes;
But what I actually get at runtime is a List<JAXBElement<AANode>> which leads into a ClassCastException.
EDIT 1:
I have missed the fact that the cxf-codegen framework is generating a class where you clearly can see that the property is annotated with JAXBElement.class which i think is wrong. Interestingly changing the annotation by hand to AANode.class will fail with an IllegalAnnotationException: AANode" or any of its subclasses are not known to this context.
public class AssetAllocation
extends DomainObject
implements Serializable, Equals, HashCode, ToString
{
#XmlElementRef(name = "nodes", type = JAXBElement.class)
protected List<AANode> nodes;
apache CXF code gen plugin will always generate codes with JAXBElement until you set the generate element property flag.
Please create Jaxb binding.xml and refer that binding xml in your code gen plugin section from pom file as below
binding.xml
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxb:bindings>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxb:bindings>
</jaxb:bindings>
code gen plugin
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/META-INF/wsdl/CxfExampleService.wsdl</wsdl>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/META-INF/wsdl/binding/bindings.xml</bindingFile>
</bindingFiles>
</wsdlOption>
</wsdlOptions>
</configuration>
</execution>
</executions>
</plugin>
This will resolve the issue
In fact the wsdl2java generates classes with wrong annotations. Instead of
#XmlElementRef(name = "nodes", type = JAXBElement.class)
protected List<AANode> nodes;
One would expect to have:
#XmlIDREF
protected List<AANode> nodes;
I was not able to manage this by bindings.xml. So my final solution is that I use a Byte-Code manipulation to fix the annotations. That way I do not have to mess around with the generated classes or with the generator itself.
I have many classes generated by JAXB's xsd2java. I need all these classes to be annotated with specific annotations at compile time (for example with lombok annotations). Is there any way to do this, with some code generation tool for example?
Disclaimer: I am the author of JAXB2 Annotate Plugin which allows you adding arbitrary annotations to the schema-derived classes.
Short example:
<xsd:complexType name="FooType">
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>#java.lang.SuppressWarnings({"unchecked","rawtypes"})</annox:annotate>
<annox:annotate target="package">#javax.annotation.Generated({"XJC","JAXB2 Annotate Plugin"})</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>#java.lang.SuppressWarnings({"unchecked","rawtypes"})</annox:annotate>
<annox:annotate target="setter">#java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter-parameter">#java.lang.Deprecated</annox:annotate>
<annox:annotate target="getter">#java.lang.Deprecated</annox:annotate>
<annox:annotate target="field">#java.lang.Deprecated</annox:annotate>
<annox:annotate target="class">#java.lang.Deprecated</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
Works in external binding files as well.
Limitations:
Annotations are provided in Java syntax, but you have to use fully qualified names.
You have to include annotations classes (lombok, for instance) into the XJC classpath as these classes must be available during the schema compilation time.
ps. I assume that when you said xsd2java you probably meant XJC.
Update
The OP asked about in comments how to configure it with the jaxb2-maven-plugin.
You can use jaxb2-annotate-plugin with jaxb2-maven-plugin as well. I just have never tried it.
You can include additional JARs into classpath by using the dependencies/depenency in pom.xml.
Then you'll need to add arguments into the configuration.
See this answer (and question) for examples:
https://stackoverflow.com/a/12804497/303810
It is about other plugins but you'll get a clue on how to configure it with Codehaus jaxb2-maven-plugin.
Configuration with my maven-jaxb2-plugin would be as follows:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<configuration>
<extension>true</extension>
<args>
<arg>-Xannotate</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-annotate-plugin-test-annox-annotations</artifactId>
</plugin>
</plugins>
</configuration>
</plugin>
This part:
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-annotate-plugin-test-annox-annotations</artifactId>
</plugin>
refers to the artifact containing the annotation classes.
Here's a sample pom.xml for maven-jaxb2-plugin/jaxb2-annotate-plugin combo.
I'm using Maven to generate the implementation code for a web service. Originally, this code was generated from a WSDL and schema using something else (probably a wizard in Eclipse). The service implementation class name that jaxws-maven-plugin generates is MyService_MyServieSOAPImpl. When this was originally generated, the implementation class was named MyService_SOAPImplementation. I'm guessing that the wizard that Eclipse uses allows the user to choose the name of the implementation class. I tried using the sei element, but it does not work. Here's a snippet of the wsimport plugin in my POM:
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<id>generateMyServiceFromWSDL</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<genJWS>true</genJWS>
<bindingDirectory>${basedir}/src/main/bindings</bindingDirectory>
<bindingFiles>
<bindingFile>otherSchema.episode</bindingFile>
</bindingFiles>
<wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
<wsdlFiles>
<wsdlFile>MyService.wsdl</wsdlFile>
</wsdlFiles>
<wsdlLocation>${project.basedir}/src/main/resources/wsdl/MyService.wsdl</wsdlLocation>
<sourceDestDir>${project.basedir}/src/main/java</sourceDestDir>
<sei>com.myCompany.MyService_SOAPImplementation</sei>
<xdonotoverwrite>true</xdonotoverwrite>
<xnocompile>true</xnocompile>
<xdebug>true</xdebug>
<verbose>true</verbose>
<target>2.0</target>
</configuration
</execution>
...
From some of the documents I've read, it looks like sei is only applicable for wsgen, not wsimport. If that is so, is there any way to force a name for the implementation class name?
UPDATE
Ok, so from my reading, it should be possible to do this with a JAX-WS binding file, not directly in the POM file.
I've created my binding file like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxws:bindings version="2.1" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
jaxws:wsdlLocation="src/main/webapp/wsdl/MyService.wsdl">
<jaxws:bindings node="wsdl:definitions/wsdl:portType[#name='MyService']">
<!-- change the generated SEI class -->
<jxb:class name="MyServiceSOAPImpl"></jxb:class>
</jaxws:bindings>
</jaxws:bindings>
But this still doesn't seem to have any effect - wsimport is still producing the implementation as MyService_MyServiceSOAPImpl.
Try changing your
<jaxws:bindings node="wsdl:definitions/wsdl:portType[#name='MyService']">
to
<jaxws:bindings node="wsdl:definitions/wsdl:service[#name='MyServiceService']">
Note that the second part of the node path is service and not portType. You would use portType to customize the service interface, not the implementation.
As an aside it's important to note that JAX-WS bindings (seemingly) need to be in their own XML file (per WSDL) and not included with JAXB bindings.
Someone may find the list of JAX-WS bindings here to be useful: http://docs.oracle.com/cd/E13222_01/wls/docs103/webserv/data_types.html#wp227312
In case this helps someone, two changes are required in OPs bindings.xml file to get it to work:
The first change was already suggested by MGE - changing the wsdl:portType in the Xpath to wsdl:service
The namespace for class name has to be 'jaxws', so
change to this:
<jaxws:class name="MyServiceSOAPImpl"/>
from
<jxb:class name="MyServiceSOAPImpl"></jxb:class>
I'm using the codehaus jaxb2-maven-plugin, v1.5 to compile XSDs into POJOs, but the generated package name coerces the package name to lower case (so, if I have my target namespace as http://example.com/sampleNamespace, then the generated package is com.example.samplenamespace).
I've googled around a bit and found mostly people having problems with underscores getting munged to dots, and the solution for that, but I can't seem to find something specific for preserving the case of the namespace.
NB: I don't want to have to repeat myself and override the generated package name, so the generatePackage option in the maven config isn't for me.
Before finding about the underscore munging, I had tried that, and also a regular space - both stick a dot in there.
Any ideas?
Schema:
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:t="http://example.com/sampleNamespace" targetNamespace="http://example.com/sampleNamespace"
jaxb:version="2.0">
<complexType name="MyFirstClass">
<sequence>
<element name="MyFirstElement" type="string" />
</sequence>
</complexType>
</schema>
Maven config:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
</plugin>
You will need to leverage a JAXB bindings file to specify a package name if you do not want to use the one that JAXB generates based on common Java coding conversions.
<bindings
xmlns="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<bindings schemaLocation="schema.xsd">
<schemaBindings>
<package name="com.example.sampleNamespace"/>
</schemaBindings>
</bindings>
</bindings>
I'm using the maven jaxb2 plugin to generate Java classes, built from schemas in a jar. However, I'm not sure how to correctly locate to these schemas from a bindings file. If Iextract the schemas from the jar and drop them in the same directory as the bindings, all is well. However, this isn't a practical long term solution.
pom.xml:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemas>
<schema>
<dependencyResource>
<groupId>com.test</groupId>
<artifactId>schemas</artifactId>
<version>1.10-SNAPSHOT</version>
<resource>schemas/schema.xsd</resource>
</dependencyResource>
</schema>
</schemas>
<bindingDirectory>bindings</bindingDirectory>
<generatePackage>test.package</generatePackage>
<bindingIncludes>
<include>*.xml</include>
</bindingIncludes>
<extension>true</extension>
</configuration>
</plugin>
bindings.xml:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb ./bindingschema_2_1.xsd"
version="2.1">
<jxb:bindings schemaLocation="classpath:/schemas/schema.xsd" node="/xs:schema">
<jxb:bindings node="//xs:complexType[#name='AbstractChangeable']">
<jxb:class implClass="com.test.AbstractEntity" />
</jxb:bindings>
</jxb:bindings>
You need to use maven-dependency-plugin:unpack and then point maven-jaxb2-plugin to outputDirectory. In this case in binding file you need to say something like schemaLocation="../target/schemas/schema.xsd"
What I'd like to have working here is something like:
<jaxb:bindings schemaLocation="maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-po!/purchaseorder.xsd" node="/xs:schema">
<jaxb:schemaBindings>
<jaxb:package name="org.jvnet.jaxb2.maven2.tests.po"/>
</jaxb:schemaBindings>
</jaxb:bindings>
But it does not at the moment. Please file an issue, I'll try to fix it.
What does work now is SCD-based binding:
<jaxb:bindings scd="x-schema::po" xmlns:po="urn:po">
<jaxb:schemaBindings>
<jaxb:package name="org.jvnet.jaxb2.maven2.tests.po"/>
</jaxb:schemaBindings>
</jaxb:bindings>
So you don't actually need to bind based on a specific schema location, you can bind based on the namespace URI, which is theoretically better.
Practically I have an experience that SCD-bindings don't always work reliably.
UPDATE
See this link for more information SCD usage in JAXB.
I know this is an old question but I was struggling with the same problem. I found that doing inline bindings would solve the problem. You would no longer have any need for the binding file and the bindings would be carried over to projects depending on it.