JAXB episode compilation with include does not work - java

I have 2 schemas A, B. I'm reusing some A elements in B.
I do not use namespaces.
I'm using
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.9.0</version>
I have have defined an inclusion of schema A in schema B as:
<xs:include schemaLocation="classpath:my.schema.A.xsd"/>
and the catalog as
REWRITE_SYSTEM "classpath:my.schema.A.xsd" "maven:my.schema:schema-a!/A.xsd"
The jaxb configuration goes:
<configuration>
<generatePackage>my.schema.b</generatePackage>
<schemaIncludes>
<includes>B.xsd</includes>
</schemaIncludes>
<episodes>
<episode>
<groupId>my.schema</groupId>
<artifactId>schema-a</artifactId>
</episode>
</episodes>
<catalog>src/main/catalog/catalog.cat</catalog>
</configuration>
The issue is that whenever I specify the episode dependency the schema does not generate any classes even though it contains some B elements I want to generate the classes for.
[INFO] Parsing input schema(s)...
[INFO] Compiling input schema(s)...
[INFO] Cleaning package directories.
[INFO] Finished execution.
When I remove the episode it works well and generates classes for schema A as well - which I indeed want to avoid.
Do you have any suggestions?
A sample was published in Jaxb episodic compilation

Ok, I've checked your example. The problem is that you don't use namespaces.
Check your META-INF/sub-jaxb.episode file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxb:bindings scd="x-schema::">
<jaxb:schemaBindings map="false">
<jaxb:package name="schema.episode.a"/>
</jaxb:schemaBindings>
<jaxb:bindings scd="person">
<jaxb:class ref="schema.episode.a.Person"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
You see this <jaxb:bindings scd="x-schema::"> and then <jaxb:schemaBindings map="false">. This basically tells XJC "don't map anything in the empty namespace". Since your second schema (b.xsd) also does not use namespaces, when you use a.xsd's episode file (binding above), you suppress generation of code for b.xsd as well.
To sum it up, when using episodes/separate schema compilation you can't put schemas with one namespace into different episodes. This is exactly the issue with include.
This is not a bug in the maven-jaxb2-plugin. I would not also call it a bug in XJC. It's just how episodes work by default.
See my pull request here, it demonstrates episodic compilation, when namespaces are handled accordingly.

Author of the maven-jaxb2-plugin here.
My guess would be that your episode says something like "don't compile namespaces A and B". Please check the binding file inside META-INF in your JAR.
This is pretty advanced usage, there's quite a number of points where this can go wrong. You use:
catalogs
Maven artifact-based schema resolution
episodes
Catalogs and episodes are XJC features, Maven resolution comes from the maven-jaxb2-plugin.
We should try to single out what fails:
Try it just with episodes - extract your schemas and compile "as is", without catalogs and resolver
Just catalogs - extract schema and rewrite to local dirs instead of maven:
Try maven:my.schema:schema-a!/A.xsd as schema location without episodes and catalogs
Obviously another three combinations to try.
If you provide a sample project, I'll investigate (but not within the next 10 days). The best would be to file an issue. I'll be moving the plugin to GitHub so this would be a good place:
https://github.com/highsource/maven-jaxb2-plugin

Related

How does xsi:schemaLocation work with IntelliJ IDEA?

I am a little confused with how does xml xsi:schemaLocation works.
I am using Maven + IDEA to create a Spring project.
If miss org.springframework.spring-beans in my dependency, IDEA will warn me some error.
If I add this jar, warn will disappear.
Maybe it is not important, but it like a black magic to me, can any one help me how does this work?
Those XSDs are in fact included in the jar provided by spring. You can check this by doing a double shift and typing in the XSD's filename. So if you don't include the jar, your maven project cannot locate the XSD in your classpath.
The XSD you mentioned can be found here, as part of the spring-beans module
IntelliJ IDEA is helpfully indicating that it cannot location the XSD that it needs to validate the Spring project.
It turns the default namespace (beans/#xmls) red because it uses that along with the paired value of the namespace given by xsi:schemaLocation (also red) in order to find the governing XSD. Note that this does not necessarily have to be at the URL given by the paired value xsi:schemaLocation (https://www.springframework.org/schema/beans/spring-beans.xsd). Other mechanisms, including as XML Catalogs, can aid in the resolution of where the actual XSD can be found.
In this case, IDEA knows to check JARs on the classpath for the needed XSD.
See also:
How to link XML to XSD using schemaLocation or noNamespaceSchemaLocation?
xmlns, xmlns:xsi, xsi:schemaLocation, and targetNamespace?
How to reference a local XML Schema file correctly?
Must an XML namespace name URI be retrievable?

How can I tell JAXB to generate classes in separate packages when two separate schemas have the same namespace?

I suspect that there's no good answer to this, but hopefully I'm missing something. Let's say I have two separate XML schemas both with the same namespace, defining some duplicate complexTypes, and I want to generate Java classes for them with JAXB. As a very simplified example:
schema1.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="namespace1" xmlns="namespace1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="xs:string"/>
</xs:schema>
and
schema2.xsd: (identical to the above)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="namespace1" xmlns="namespace1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="xs:string"/>
</xs:schema>
When I try to generate these with JAXB (Ant XJC task via gradle), I get the following, entirely reasonable error:
[ant:xjc] [ERROR] 'foo' is already defined
[ant:xjc] line 3 of file:/C:/dev/test/src/main/resources/schema2.xsd
[ant:xjc]
[ant:xjc] [ERROR] (related to above error) the first definition appears here
[ant:xjc] line 3 of file:/C:/dev/test/src/main/resources/schema1.xsd
As per the JAXB docs, I tried specifying the package in an external customisation file like this:
<jaxb:bindings schemaLocation="schema1.xsd">
<jaxb:schemaBindings>
<jaxb:package name="package1"/>
</jaxb:schemaBindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="schema2.xsd">
<jaxb:schemaBindings>
<jaxb:package name="package2"/>
</jaxb:schemaBindings>
</jaxb:bindings>
but that doesn't work - I then realised that the same docs linked above say:
Note that this customization is per namespace. That is, even if your schema is split into multiple schema documents, you cannot put them into different packages if they are all in the same namespace.
So, I'm guessing that's never going to work.
Is there any sensible approach to this? I suspect the correct answer is that the schemas should be in different namespaces, as that would resolve the issue, and probably make more logical sense, but I don't have any control over the schemas - they are provided by a 3rd party. I've asked if it's possible to change them, but I suspect the answer is no.
The only other option I can see is to generate the Java classes twice, first for schema1.xsd, and then separately for schema2.xsd, each time with their own customisation file specifying a different package, but that feels like a very clumsy solution. Is there any more sensible option that I'm missing?
You can't. Packages are generated based on namespaces. Same namespace - same package.
You have to do several executions in this case. Also mind to use different output generation directories (like target/generated-sources/xjc1, target/generated-sources/xjc2) otherwise "compile only if anything was changed" won't work correctly.

Resolving conflicts when generating code with CXF and wsdl2java

I'm struggling with some conflicts during code generation from a bunch of WSDL files using wsdl2java via the cxf-codegen-plugin with Maven. The WSDLs declare different APIs of the same system, and the generated code has some amount of overlap (especially with the model classes). The external system and the WSDLs come from a third party and are therefore not controlled by us.
The first problem I have is a naming conflict in one of the resulting ObjectFactory classes caused by one of the WSDLs. It defines a complexType with the name Foo that contains an element with the name Status, and it also defines a element with the name FooStatus. When generating the code, JAXB throws a fit because the ObjectFactory would have two factory methods with the name createFooStatus(...) and I end up with an exception during runtime. I've tried providing the option -autoNameResolution to wsdl2java with no avail. I've looked at "Two declarations cause a collision in the ObjectFactory class" and "Applying external JAXB binding file to schema elements imported from WSDL", and based on those I've written an external binding file that renames one of the factory methods. I use SCD instead of XPath in the binding file as shown in the latter link, because I had the same problem with XPath as the author. This works, but only if I process the WSDL files individually and apply the binding file only to the WSDL that causes the conflict. The Maven configuration looks like this:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.0.0-milestone1</version>
<executions>
<execution>
<id>generate-proxies</id>
<phase>generate-sources</phase>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/First.wsdl</wsdl>
<bindingFiles>
<bindingFile>${basedir}/bindings.xml</bindingFile>
</bindingFiles>
</wsdlOption>
<wsdlOption>
<wsdl>${basedir}/Second.wsdl</wsdl>
</wsdlOption>
<wsdlOption>
<wsdl>${basedir}/Third.wsdl</wsdl>
</wsdlOption>
... More wsdlOption declarations ...
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
Now, if I do this I end up with another problem, because the generated code from the different WSDL files uses the same package structure. What this means in practice is that the ObjectFactory classes get overridden when processing subsequent WSDL files, meaning that only the one generated from the last WSDL will exist after the plugin execution. I know that I could change the target package structure, but the code generated from the different WSDLs has a lot of overlap and it would feel silly to duplicate it. I've also tried using the -keep wsdl2java option, but that doesn't seem to do anything (or at least the ObjectFactory classes still get overridden). My understanding is that the solution to this would be to process all of the WSDLs in one go with a Maven configuration like this (showing only the configuration section, all else stays the same):
<configuration>
<defaultOptions>
<bindingFiles>
<bindingFile>${basedir}/bindings.xml</bindingFile>
</bindingFiles>
</defaultOptions>
<wsdlRoot>${basedir}</wsdlRoot>
<includes>
<include>*.wsdl</include>
</includes>
</configuration>
However, this results in a com.sun.istack.SAXParseException2, saying that my SCD expression doesn't match any schema component (since the schema component exists only in one of the WSDLs).
I can get the result I want if I modify the WSDL file itself and use the latter Maven configuration without the binding file. By doing this, the resulting ObjectFactory is a merge from the ones that would be created when processing the WSDLs individually with the first Maven config. However, I'd rather not do that, but instead would like to manage this with an external binding file. How should I go about solving this? Can I write/apply the binding file so that no exception is raised if the matching schema component is not found? Or can I process the WSDLs individually and not overwrite the ObjectFactory classes? Or do I just have to suck it up and either generate the code from different WSDLs to different packages or edit the WSDL files themselves? Just in case it matters, my current binding file looks like this (the WSDLs are located inside my project in the same directory with the binding file):
<bindings scd="x-schema::tns" xmlns:tns="NamespaceOfFoo" xmlns="http://java.sun.com/xml/ns/jaxb" version="2.1">
<bindings scd="tns:FooStatus">
<factoryMethod name="FooStatusType"/>
</bindings>
</bindings>
I eventually solved this myself after some more googling around and reading forum posts. I managed to write the external binding file using XPath (instead of SCD) in a way that only targets the node I'm interested in without giving an error when processing the other WSDL files. The main source of confusion that initially prevented me from targeting nodes in the WSDL with XPath was the similar XML schemas of the JAXB and JAXWS namespaces (both define the element 'bindings', and most tutorials I've seen used the JAXB version while here I had to use the JAXWS version). The resulting binding file looks like this:
<jaxws:bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
wsdlLocation="First.wsdl"
version="2.1">
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema/xsd:element[#name='FooStatus']">
<jaxb:factoryMethod name="FooStatusType"/>
</jaxws:bindings>
</jaxws:bindings>

Unsupported binding namespace while generating class files using xjc

I tried googling without any help. Apologies if there are any duplicates.
I have the following schema header for the file common.xsd
<xs:schema xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:meta="http://www.vmware.com/vcloud/meta"
jaxb:version="2.0"
jaxb:extensionBindingPrefixes="meta"
elementFormDefault="qualified"
targetNamespace="http://www.vmware.com/vcloud/v1.5"
version="1.0">
I am trying to generate class files using xjc command.
xjc -version
xjc version "JAXB 2.1.10 in JDK 6"
JavaTM Architecture for XML Binding(JAXB) Reference Implementation, (build JAXB 2.1.10 in JDK 6)
I am getting this error.
[info] [ERROR] Unsupported binding namespace "http://www.vmware.com/vcloud/meta". Perhaps you meant "http://java.sun.com/xml/ns/jaxb/xjc"?
[info] line 21 of file:/Users/kcherivirala/vmware/dev/corp/zephyr/services/networkservice/app/vcd-schema/src/main/xsd/vcloud/common.xsd
Any leads on this would be of great help.
The problem is here:
jaxb:extensionBindingPrefixes="meta"
jaxb:extensionBindingPrefixes declares prefixes of the vendor customization namespaces. See this link.
The JAXB RI provides additional customizations that are not defined by
the JAXB specification. Note the following:
These features may only be used when the JAXB XJC binding compiler is
run in the -extension mode.
All of the JAXB RI vendor extensions are defined in the
"http://java.sun.com/xml/ns/jaxb/xjc" namespace.
The namespaces containing extension binding declarations are specified
to a JAXB processor by the occurrence of the global attribute
#jaxb:extensionBindingPrefixes within an instance of
element. The value of this attribute is a whitespace-separated list of
namespace prefixes. For more information, please refer to section
6.1.1 of the JAXB Specification.
You only need this when you customize the binding. For instance you may use xjc:superClass to customize to extend a common super class. In this case, xjc would be in jaxb:extensionBindingPrefixes.
If you just compile your schema, the prefix of your schema will most definitely NOT be in jaxb:extensionBindingPrefixes. So, XJC just complained it was there but was not a binding extension.

JAXB, XJC -> create multiple class files

I'm using JAXB and XJC for first time.
I would like to generate Java classes from XML file so I use this online helper to generate schema from XML file.
After that I just use this command line to generate Java classes :
xjc myschema.xsd
it's work but I receive only one Java file and many static classes inside it. Is this possible to generate many java files that contain only one classe per file please ?
Thank you
By default JAXB (JSR-222) will create static inner classes for nested complex types to prevent class name conflicts. You can use an external binding file to disable this behaviour.
binding.xml
A binding file allows you to customize how Java classes are generated from an XML schema.
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>
XJC Call
The -b option is used with the XJC command to specify a binding file.
xjc -b binding.xml myschema.xsd
For More Information
http://blog.bdoughan.com/2011/07/jaxb-xjc-and-nested-classes.html

Categories