I have this Maven "task" to generate Java classes from an XSD file using JAXB.
<!-- XML to Java classes -->
<plugin>
<groupId>com.sun.tools.xjc.maven2</groupId>
<artifactId>maven-jaxb-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<generatePackage>nl.compay.service</generatePackage>
<schemaDirectory>src/main/webapp/compay</schemaDirectory>
</configuration>
</plugin>
For an XSD type "User", it generates a class named "User" (duh). However, I also have a JPA entity class called "User" (though in a different package).
Can I change the XML config above to let JAXB prefix the generated classes with something like "XML"?
This is a common requirement. You can do that by providing an additional JAXB binding file to customize how JAXB translates the Schema type names into Java class names.
These files normally end in extension ".xjb". You need to create one for your schema, for example:
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="nl.company.service.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:nameXmlTransform>
<jxb:typeName prefix="XML"/>
<jxb:anonymousTypeName prefix="XML"/>
</jxb:nameXmlTransform>
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
After you've done that, drop the xjb file somewhere in your build directory and tell Maven to make use of it during translation:
<includeBindings>
<includeBinding>mybindings.xjb</includeBinding>
</includeBindings>
And here's a hint for the road: if you are in a path that contains spaces (e.g. "Documents and Settings\user\project") then JAXB will fall over with strange errors.
Related
I am using globalBindings in JAXB to generate Serializable classes.
<jaxb:globalBindings>
<xjc:simple />
<xjc:serializable uid="1" />
</jaxb:globalBindings>
The uid attribute is generated in the java classes as the following:
private final static long serialVersionUID = 1L;
I understand that "final static" and "static final" are the same and the generated serializable classes can also be compiled. But we are getting error from SonarQube of using "final static" instead of "static final".
We are currently manually changing the attribute to "static final" to bypass the SonarQube issue. But can anyone suggest if it is possible to have JAXB to generate "static final" instead?
We are using JAXB2 and this is the pom.xml.
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.3.1</version>
<dependencies>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
<execution>
<id>someID</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/src/main/resources/some.xsd</source>
</sources>
<xjbSources>
<xjbSource>src/main/resources/some.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
From my point of view, it is not really reasonable to check the generated code.
If SonarQube complains about private final static but not private static final, just ignore it. It does not matter, especially not in the generated code.
Now, to answer your question - you can write an XJC plugin which would generate static final instead. Here's an article on it. You can find further examples in JAXB2 Basics.
Disclaimer: I am the author of JAXB2 Basics which is a package of XJC plugins.
I want to generate java classes through XSDs, I want to use/include one XSD file in another but when I include them in another XSDs same java class is generated in both the packages. I am also using maven-jaxb2-plugin plugin
Do separate - aka modular - schema compilation using so-called episodes. That is to say, if you want to import schema A into schema B and generate classes for schema B, you first create a separate Maven project in order to compile schema A to a separate Maven artifact with maven-jaxb2-plugin as usual. (This is assuming the schema A stands alone, i.e. does not import any other schema; else you have to repeat the same process on the imported schema(s).) As a result, you get A.jar with the generated classes only from schema A, and most importantly, a META-INF/sun-jaxb.episode file. This file provides information about the existing XSD-to-Java bindings, and this will tell the maven-jaxb2-plugin (in fact the xjc tool underlying maven-jaxb2-plugin) what has already been generated from the schema, and therefore prevent it to re-generate the same classes again.
Then you create another Maven project in order to compile schema B, with maven artifact of A.jar among its Maven dependencies. This time, in the configuration of maven-jaxb2-plugin, you set the configuration parameter useDependenciesAsEpisodes to true. This will tell the plugin to use the .episode files from all dependencies (when there is any). You can find a basic example on the plugin's GitHub wiki. Below is a real-life example from AuthzForce project, an XACML implementation, where the OASIS XACML standard schema (xacml-core-v3-schema-wd-17.xsd) imports the W3C standard XML namespace schema (xml.xsd). Therefore, you have one Maven project/artifact for the xml.xsd, and another one for the XACML schema, where the relevant parts of the POM look like this:
<project ...>
...
<dependencies>
...
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>${artifactId.prefix}-xmlns-model</artifactId>
<version>${project.parent.version}</version>
</dependency>
...
</dependencies>
<build>
<plugins>
...
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<configuration>
<verbose>true</verbose>
<extension>true</extension>
<strict>false</strict>
<useDependenciesAsEpisodes>true</useDependenciesAsEpisodes>
...
<catalog>src/main/jaxb/catalog.xml</catalog>
<schemaDirectory>src/main/resources</schemaDirectory>
<schemaIncludes>
<include>xacml-core-v3-schema-wd-17.xsd</include>
</schemaIncludes>
</configuration>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
You notice that there is also a catalog parameter pointing to the XML catalog file. This is also important because this catalog will enable the plugin to locate the A.xsd file (xml.xsd in my example) directly in its maven artifact, so that you don't need to duplicate the file in project B or elsewhere. In my example, since the XACML schema imports xml.xsd as follows:
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
... the catalog.xml must look like this:
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<system systemId="http://www.w3.org/2001/xml.xsd" uri="maven:org.ow2.authzforce:authzforce-ce-xmlns-model:jar!/xml.xsd" />
</catalog>
You notice that the uri parameter references the xml.xsd from its Maven artifact. For more info on this syntax to refer to Maven artifact resources, refer to the maven-jaxb2-plugin's wiki.
In general, to allow maximum flexibility and simplicity in managing schema locations, I recommend to specify only the namespace in schema imports. (No schemaLocation.) For example, prefer this:
<xs:import namespace="http://www.w3.org/XML/1998/namespace" />
... in which case the catalog.xml should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<public publicId="http://www.w3.org/XML/1998/namespace" uri="maven:org.ow2.authzforce:authzforce-ce-xmlns-model:jar!/xml.xsd" />
</catalog>
(This is not the case in my example exceptionally, because the official XACML schema from the standard committee uses a schemaLocation, so it's preferable to keep it as is like the original.)
I am trying to enforce enum validation for my generated JAXB classes, but I am having some issues with getting them bound.
The basic XSD setup is:
-enumsXSD
-2 other XSDs that import this XSD
To provent duplication of my classes I am using episodes, but it looks like this does not play nice when adding annotions in the enumsXSD
com.sun.istack.SAXParseException2: compiler was unable to honor this annox:annotateEnumValueMethod customization. It is attached to a wrong place, or its inconsistent with other bindings.
[ERROR] Error while generating code.Location [ file:somewhere/generic.episode{64,99}].
com.sun.istack.SAXParseException2: (the above customization is attached to the following location in the schema)
The code:
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.13.3</version>
<configuration>
<extension>true</extension>
<args>
<arg>-Xannotate</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>1.0.4</version>
</plugin>
</plugins>
</configuration>
<executions>
<!--GENERIC ENUMS -->
<execution>
<id>ENUMS</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<extension>true</extension>
<generatePackage>com.foo.generic.enums</generatePackage>
<generateDirectory>${project.build.directory}/generated-sources/xjc1/generic</generateDirectory>
<!-- Define the directory where we should find the XSD files -->
<schemaDirectory>
src/main/resources/dtd/generic
</schemaDirectory>
<schemaIncludes>
<source>enums.xsd</source>
</schemaIncludes>
<episodeFile>
${project.build.directory}/generated-sources/xjc1/generic/META-INF/generic.episode
</episodeFile>
</configuration>
</execution>
<execution>
<id>A_XSD</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<extension>true</extension>
<bindingDirectory>${project.build.directory}/generated-sources/xjc1/generic/META-INF</bindingDirectory>
<bindingIncludes>
<include>generic.episode</include>
</bindingIncludes>
<!-- Set the package of the generated code -->
<generatePackage>com.foo.something</generatePackage>
<generateDirectory>${project.build.directory}/generated-sources/xjc1/a_something</generateDirectory>
<!-- Define the directory where we should find the XSD files -->
<schemaDirectory>
src/main/resources/dtd/someplace/a/
</schemaDirectory>
<schemaIncludes>
<source>*.xsd</source>
</schemaIncludes>
</configuration>
</execution>
</executions>
<plugin>
</plugins>
And in the enums XSD
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" id="commonEnums"
targetNamespace="http://foo.com/xsd/commons/enum"
xmlns:xs="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">
<xs:simpleType name="bulletinCategory">
<xs:annotation>
<xs:appinfo>
<annox:annotateEnumValueMethod>#java.lang.Deprecated</annox:annotateEnumValueMethod>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="valueA" />
<xs:enumeration value="valueB" />
<xs:enumeration value="valueC" />
</xs:restriction>
</xs:simpleType>
</xs>
Ideally speaking the #deprecated should be #XmlJavaTypeAdapter(FooAdapter.class) but I thought let's start small.
The problem is probably that you've included customizations directly into the enums.xsd. So when you compile other schemas, these customizations are considered as well.
But since you also seem to use the enums.xsd as episode, this effectively prevents generation of enum classes. With no enum classes, customizations cannot be applied so they are not marked as "recognized" and this produces the error you get.
To solve this, when compiling enums.xsd, simply move customizations into a separate bindings file and use it during compilation.
Then, when compiling other schemas, use enums.xsd as episode but do not use that bindings file with customizations for enums.xsd.
The instructions to generate schema through running "schenagen" as suggested in Java API documentation worked with JDK7, but not with JDK8.
Here is the documentation page:
http://download.java.net/jdk8/docs/technotes/guides/xml/jaxb/index.html
Here is the line from this page with links to the instructions:
"
Running the schema generator (schemagen): [command-line instructions, using the SchemaGen Ant task]
"
Schema generator does not work because some classes have been removed from JDK8:
"java.lang.ClassNotFoundException: com.sun.mirror.apt.AnnotationProcessorFactory"
There is another solution suggested here:
Generating XSD schemas from JAXB types in Maven?
This solution also works with JDK7 but not with JDK8; it will end up with a similar error:
"Class not foundcom/sun/tools/apt/Main.class"
The root cause is probably the same: the annotation processing tools are removed from JDK8.
This change was planned in JEP 117 long time ago:
http://openjdk.java.net/jeps/117
How can I generate an XML schema file from (JAXB) annotated Java classes now, using JDK8?
This was a bug in the "jaxb2-maven-plugin". You must use the version 1.6 or later of the plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<goals>
<goal>schemagen</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<includes>
<include>com/projectname/model/*.java</include>
</includes>
<outputDirectory>${project.build.directory}/schemas</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
You can use the generateSchema method on JAXBContext to generate an XML Schema:
http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/JAXBContext.html#generateSchema%28javax.xml.bind.SchemaOutputResolver%29
I'm trying to generated Java classes from a set of XSD files using the Maven XJC plugin with a custom binding. The customization is added to prefix JAXB generated classes. When the maven build runs, however, the XJC plugin doesn't seem to recognize the schemaBindings element and throws the exception as under.
[ERROR] Error while parsing schema(s).Location [ file:/C:/blah/bindings.xjb{5,25}].
com.sun.istack.SAXParseException2: The "jaxb:schemaBindings" customization is no
t associated with any schema element.
at com.sun.tools.xjc.reader.internalizer.Internalizer.reportError(Intern
alizer.java:632)
at com.sun.tools.xjc.reader.internalizer.Internalizer.reportError(Intern
alizer.java:626)
at com.sun.tools.xjc.reader.internalizer.Internalizer.move(Internalizer.
java:451)
at com.sun.tools.xjc.reader.internalizer.Internalizer.transform(Internal
izer.java:160)
at com.sun.tools.xjc.reader.internalizer.Internalizer.transform(Internal
izer.java:109)
at com.sun.tools.xjc.reader.internalizer.DOMForest.transform(DOMForest.j
ava:449)
at com.sun.tools.xjc.ModelLoader.buildDOMForest(ModelLoader.java:345)
at com.sun.tools.xjc.ModelLoader.loadXMLSchema(ModelLoader.java:377)
at com.sun.tools.xjc.ModelLoader.load(ModelLoader.java:174)
at com.sun.tools.xjc.ModelLoader.load(ModelLoader.java:119)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.loadModel(XJC22Mojo.java:45)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.doExecute(XJC22Mojo.java:35)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.doExecute(XJC22Mojo.java:22)
at org.jvnet.jaxb2.maven2.RawXJC2Mojo.doExecute(RawXJC2Mojo.java:282)
at org.jvnet.jaxb2.maven2.RawXJC2Mojo.execute(RawXJC2Mojo.java:147)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPlugi
nManager.java:490)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(Defa
ultLifecycleExecutor.java:694)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLi
fecycle(DefaultLifecycleExecutor.java:556)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(Defau
ltLifecycleExecutor.java:535)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHan
dleFailures(DefaultLifecycleExecutor.java:387)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegmen
ts(DefaultLifecycleExecutor.java:348)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLi
fecycleExecutor.java:180)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:6
0)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
The bindings.jxb is as follows.
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
jaxb:version="2.1" schemaLocation="blah.xsd">
<jaxb:schemaBindings>
<jaxb:nameXmlTransform>
<jaxb:elementName suffix="Type"/>
</jaxb:nameXmlTransform>
</jaxb:schemaBindings>
</jaxb:bindings>
The following plugins are used for the generating the Java Classes. Pasting the relevant mvn snippet here.
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.6</version>
</dependency>
</dependencies>
<configuration>
<schemaDirectory>./src/main/resources</schemaDirectory>
<includeBindings>
<includeBinding>**/*.xjb</includeBinding>
</includeBindings>
<extension>true</extension>
</configuration>
</plugin>
The only other discussion I could find on this issue revolves about JAX-WS which I don't use as there's no WSDL files involved here. It's all XSD files here.
I don't see why this error has to occur because the JAXB's binding.xsd file indeed defines the schemaBindings element as seen below.
<xs:element name="schemaBindings" substitutionGroup="jaxb:declaration">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="jaxb:package"/>
<xs:element minOccurs="0" ref="jaxb:nameXmlTransform"/>
</xs:sequence>
<xs:attribute name="map" type="xs:boolean" />
</xs:complexType>
</xs:element>
Any hints on this problem would be very much appreciated. Please let me know if more inputs are needed. Thanks!
EDIT:
A lot of people on the Internet seem to have used the schemaBindings without any issues. May be this is an issue with the dependencies mentioned in the question?
Your jaxb:schemaBindings must associate bindings with a certain schema schema. Via schema location or scd.
Please see http://jaxb.java.net/guide/Customizing_Java_packages.html