How generate XMLElementWrapper annotation with xjc and customized binding - java

I'm using JAXB and xjc to compile my XML Schema into Java classes. I do not want to manually edit this generated classes. I have xml schema like that:
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element ref="item" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
The xjc generates a class Items that only contains a list of Item objects. Is there any chance to omit the class Items and have a list of Item objects directly in the Rootclass?
I know that this can be done with #XMLElementWrapper annotation, but I don't know how to tell xjc to create such.
Thanks for any suggestions!
Best regards,
Markus

Bjarne Hansen developed a plugin for xjc that was able to take care of this. Unfortunately, the link to the original implementation is now dead. However, there is a project by Dmitry Katsubo on github, based on Bjarne's original code with some additional improvements.
→ https://github.com/dmak/jaxb-xew-plugin
(Just for reference: the original link, now dead: http://www.conspicio.dk/blog/bjarne/jaxb-xmlelementwrapper-plugin)

First lets break up your schema so that there are no inner classes generated:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="root" type="Root" />
<xs:complexType name="Root">
<xs:sequence>
<xs:element name="items" type="Items" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Items">
<xs:sequence>
<xs:element name="item" type="xs:string" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:schema>
You'll still get extra classes, just not all in one file. Now you want to add a section to your build to use the jaxb-xew-plugin. I use Maven, so for me this looks like:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<args>
<arg>-no-header</arg>
<arg>-Xxew</arg>
<arg>-Xxew:instantiate lazy</arg>
<arg>-Xxew:delete</arg>
</args>
<plugins>
<plugin>
<groupId>com.github.jaxb-xew-plugin</groupId>
<artifactId>jaxb-xew-plugin</artifactId>
<version>1.0</version>
</plugin>
</plugins>
</configuration>
</execution>
</executions>
</plugin>
If you start using namespaces so that your generated classes have package names, leave off the -Xxew:delete flag, as there's a bug that I recently fixed where it was deleting objects it shouldn't. Alternatively, you could grab the code from github and use it as 1.1-SNAPSHOT.
When I do that I get the code generated that I think you're looking for:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Root", propOrder = {
"items"
})
public class Root {
#XmlElementWrapper(name = "items", required = true)
#XmlElement(name = "item")
protected List<String> items;
public List<String> getItems() {
if (items == null) {
items = new ArrayList<String>();
}
return items;
}
public void setItems(List<String> items) {
this.items = items;
}
}

Related

Import namespace in WSDL result in JAXP09020006: The argument 'systemId' can not be null

I am reformatting the existing question that did not get any answer nor comment.
I am trying to import WSDL with Netbeans 11, using Java 11 and Maven 3.6.1. The same approach is already used for Netbeans 8 and Java 8.2 without problems, though:
the old system is Linux and the new system is Win10,
jaxws-maven-plugin 2.5 from org.codehaus.mojo is used on old system and jaxws-maven-plugin 2.3.2 from com.sun.xml.ws is used on new system
I have researched the problem down to import namespace part of my WSDL.
Here is the problematic WSDL, I have removed all features and removed references to company names:
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://XYZ/DTROrchestrator" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="DTROrchestratorService" targetNamespace="http://XYZ/DTROrchestrator">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://XYZ/datatypes/tehnicalException" targetNamespace="http://XYZ/datatypes/tehnicalException" version="1.0">
<xs:complexType name="TechnicalExceptionInfoType">
<xs:sequence>
<xs:element minOccurs="0" name="ExceptionClass" type="xs:string"/>
<xs:element minOccurs="0" name="SubCode" type="xs:string"/>
<xs:element maxOccurs="unbounded" minOccurs="0" name="Description" type="xs:string"/>
<xs:element minOccurs="0" name="StackTraceString" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://XYZ/DTROrchestrator" xmlns:ns2="http://XYZ/datatypes/tehnicalException" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://XYZ/DTROrchestrator" version="1.0">
<xs:import namespace="http://XYZ/datatypes/tehnicalException"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="TechnicalException">
<wsdl:part element="tns:TechnicalExceptionInfo" name="TechnicalException">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="DTROrchestratorPort">
</wsdl:portType>
<wsdl:binding name="DTROrchestratorServiceSoapBinding" type="tns:DTROrchestratorPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<wsdl:service name="DTROrchestratorService">
<wsdl:port binding="tns:DTROrchestratorServiceSoapBinding" name="DTROrchestratorPort">
<soap:address location="http://XYZ:9203/DTROrchestrator/2.0.0"/>
</wsdl:port>
</wsdl:service>
This is a message from build
[DEBUG] cmd.exe /X /C ""C:\Program Files\Java\jdk-11.0.3\bin\java.exe" -Djavax.xml.accessExternalSchema=all -cp /C:/Users/Robert/.m2/repository/com/sun/xml/ws/jaxws-maven-plugin/2.3.2/jaxws-maven-plugin-2.3.2.jar org.jvnet.jax_ws_commons.jaxws.Invoker com.sun.tools.ws.wscompile.WsimportTool -pathfile C:\Users\Robert\AppData\Local\Temp\jax-ws-mvn-plugin-cp4115475835641866701.txt -keep -s C:\Users\Robert\MYAPP\MYAPP092\target\generated-sources\jaxws-wsimport -d C:\Users\Robert\MYAPP\MYAPP092\target\classes -verbose -encoding UTF-8 -extension -Xnocompile -catalog C:\Users\Robert\MYAPP\MYAPP092\src\jax-ws-catalog.xml -wsdllocation http://localhost/wsdl/DTROrchestrator.wsdl -b C:\Users\Robert\MYAPP\MYAPP092\src\jaxws\dtrorchestrator\dtrorchestrator-wsdlbindings.xml file:/C:/Users/Robert/MYAPP/MYAPP092/src/wsdl/DTROrchestrator/DTROrchestrator.wsdl"
parsing WSDL...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jvnet.jax_ws_commons.jaxws.Invoker.main(Invoker.java:74)
Caused by: java.lang.NullPointerException: JAXP09020006: The argument 'systemId' can not be null.
at java.xml/javax.xml.catalog.CatalogMessages.reportNPEOnNull(CatalogMessages.java:129)
at java.xml/javax.xml.catalog.CatalogResolverImpl.resolveEntity(CatalogResolverImpl.java:70)
at com.sun.tools.xjc.ModelLoader$1.resolveEntity(ModelLoader.java:398)
at com.sun.xml.xsom.impl.parser.NGCCRuntimeEx.resolveRelativeURL(NGCCRuntimeEx.java:191)
at com.sun.xml.xsom.impl.parser.NGCCRuntimeEx.importSchema(NGCCRuntimeEx.java:256)
at com.sun.xml.xsom.impl.parser.state.importDecl.action0(importDecl.java:56)
at com.sun.xml.xsom.impl.parser.state.importDecl.leaveElement(importDecl.java:167)
at com.sun.xml.xsom.impl.parser.state.NGCCRuntime.endElement(NGCCRuntime.java:289)
at java.xml/org.xml.sax.helpers.XMLFilterImpl.endElement(XMLFilterImpl.java:570)
at com.sun.tools.xjc.util.SubtreeCutter.endElement(SubtreeCutter.java:82)
at java.xml/org.xml.sax.helpers.XMLFilterImpl.endElement(XMLFilterImpl.java:570)
at java.xml/org.xml.sax.helpers.XMLFilterImpl.endElement(XMLFilterImpl.java:570)
at com.sun.tools.xjc.reader.xmlschema.parser.CustomizationContextChecker.endElement(CustomizationContextChecker.java:169)
at java.xml/org.xml.sax.helpers.XMLFilterImpl.endElement(XMLFilterImpl.java:570)
at com.sun.tools.xjc.reader.internalizer.DOMForestScanner$LocationResolver.endElement(DOMForestScanner.java:110)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:225)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:251)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:220)
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:97)
at com.sun.tools.xjc.reader.internalizer.DOMForestScanner.scan(DOMForestScanner.java:62)
at com.sun.tools.xjc.reader.internalizer.DOMForestScanner.scan(DOMForestScanner.java:70)
at com.sun.tools.xjc.reader.internalizer.DOMForestParser.parse(DOMForestParser.java:74)
at com.sun.tools.xjc.ModelLoader$XMLSchemaParser.parse(ModelLoader.java:210)
at com.sun.xml.xsom.impl.parser.NGCCRuntimeEx.parseEntity(NGCCRuntimeEx.java:351)
at com.sun.xml.xsom.impl.parser.ParserContext.parse(ParserContext.java:98)
at com.sun.xml.xsom.parser.XSOMParser.parse(XSOMParser.java:141)
at com.sun.xml.xsom.parser.XSOMParser.parse(XSOMParser.java:130)
at com.sun.tools.xjc.ModelLoader.createXSOM(ModelLoader.java:475)
at com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.bind(SchemaCompilerImpl.java:239)
at com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.bind(SchemaCompilerImpl.java:65)
at com.sun.tools.ws.processor.modeler.wsdl.JAXBModelBuilder.bind(JAXBModelBuilder.java:112)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.buildJAXBModel(WSDLModeler.java:2268)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.internalBuildModel(WSDLModeler.java:168)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.buildModel(WSDLModeler.java:111)
at com.sun.tools.ws.wscompile.WsimportTool.buildWsdlModel(WsimportTool.java:414)
at com.sun.tools.ws.wscompile.WsimportTool.run(WsimportTool.java:175)
at com.sun.tools.ws.wscompile.WsimportTool.run(WsimportTool.java:153)
... 5 more
If line with xs:import namespace="..." is removed then there is no error (only warning about the empty WSDL that is due to removal of all features).
EDIT: If complexType is moved into an external xsd, then there is also no error!
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://XYZ/DTROrchestrator" xmlns:ns2="http://XYZ/datatypes/tehnicalException" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://XYZ/DTROrchestrator" version="1.0">
<xs:import namespace="http://XYZ/datatypes/tehnicalException" schemaLocation="tehnicalexception.xsd"/>
</xs:schema>
But this solution give me unsolved problems with bindings and thus I am still looking for solution with embedded XSD. Please, answer I you have any idea.
I have some info. Now I know, that the problem started when I set maven to use Java 11. This was the critical difference between the old and new system.
Further, I have resolved the problem by removing the whole <dependencies> and <configuration> part from the jaxws-maven-plugin description. These parts were added long ago and they were obviously not correct, anymore.
Thus, now I have only this:
<plugin>
<!-- Maven plugin for JAX-WS RI -->
<!-- https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-maven-plugin -->
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3.3</version>
<!-- <dependencies> ... </dependencies> REMOVED -->
<!-- <configuration> ... </configuration> REMOVED -->
<executions>
...
</executions>
</plugin>
EDIT: I forget to mention, that I changed maven-shade-plugin to maven-assembly-plugin. Using the first one I still get error (though a different one).
BTW: To be able to compile my SOAP client with Java 11 is a long story, this was not the only problem. Finally, I have everything working.

JAXB Overwriting package-info.java: What should be "namespace"?

We're using xjc to generate JAXB Java classes for XML generation. Everything works fine except we tried to adjust the generated namespace prefixes as described here. We're stuck with "solution 2", adjusting package-info.java, due to the JAXB version we're using.
The structure we have is several imports deep: root namespace imports other namespace, which in turn imports yet a third one.
MCVE xsds
root.xsd (imports other.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="root" xmlns:other="other" targetNamespace="root" version="1.0">
<xs:import namespace="other" schemaLocation="other.xsd" />
<xs:element name="rootElem">
<xs:complexType>
<xs:choice>
<xs:element ref="rootElem1"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="rootElem1" nillable="false">
<xs:complexType>
<xs:sequence>
<xs:element name="data">
<xs:complexType>
<xs:choice>
<xs:element ref="other:otherElem"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
other.xsd (imports third.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:other="other" xmlns:third="third" targetNamespace="other" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">
<xsd:import namespace="third" schemaLocation="third.xsd" />
<xsd:element name="otherElem">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="third:thirdElem" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
third.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:third="third" targetNamespace="third" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">
<xsd:element name="thirdElem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="thirdData" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
With this
Simple test case
#Test
public void test() throws JAXBException
{
Marshaller marshaller = JAXBContext.newInstance("test.jaxb.generated").createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.com/schema.xsd");
RootElem root = new RootElem();
RootElem1 root1 = new RootElem1();
Data d = new Data();
OtherElem other = new OtherElem();
ThirdElem thirdElem = new ThirdElem();
thirdElem.setThirdData("third");
other.setThirdElem(thirdElem);
d.setOtherElem(other);
root1.setData(d);
root.setRootElem1(root1);
Path path = Paths.get("target", "outfile.xml");
Result result = new StreamResult(path.toFile());
marshaller.marshal(root, result);
}
this results in this
Generated XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:rootElem xmlns:ns2="other" xmlns:ns3="third" xmlns:ns4="root" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/schema.xsd">
<ns4:rootElem1>
<data>
<ns2:otherElem>
<ns3:thirdElem>
<ns3:thirdData>third</ns3:thirdData>
</ns3:thirdElem>
</ns2:otherElem>
</data>
</ns4:rootElem1>
</ns4:rootElem>
and everything is fine (except data which doesn't have any namespace associated, I'm assuming because that's an inner type).
Now this is partly the question: here's the
generated package-info.java
#javax.xml.bind.annotation.XmlSchema(namespace = "other", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package test.jaxb.generated;
Why is the namespace given referring to other? My root namespace is root. (root.xsd is the only file we're giving our Maven jaxb2-maven-plugin; we can include the others, it makes no difference).
Wrong replacement package-info.java
If we overwrite the generated one with this:
#javax.xml.bind.annotation.XmlSchema(
namespace = "root",
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "t", namespaceURI = "third"),
#javax.xml.bind.annotation.XmlNs(prefix = "o", namespaceURI = "other"),
#javax.xml.bind.annotation.XmlNs(prefix = "r", namespaceURI = "root")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package test.jaxb.generated;
which we initially did because we assumed we have to give the root namespace here - this is the
Wrong Generated XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<r:rootElem xmlns:t="third" xmlns:o="other" xmlns:r="root" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/schema.xsd">
<r:rootElem1>
<data>
<r:otherElem>
<t:thirdElem>
<t:thirdData>third</t:thirdData>
</t:thirdElem>
</r:otherElem>
</data>
</r:rootElem1>
</r:rootElem>
Now the namespaces are pretty, but wrong! otherElem belongs to o, not r.
Changing the namespace in the overwriting file back to other fixes the error, but again:
the question is why is the required namespace other here? Just as confusing is the fact that the third imported layer is correct either way.
The problem is fixed, but we'd like to understand the concept. What are we missing?
EDIT:
For completeness' sake, here's the build section of my pom.xml:
<build>
<plugins>
<plugin>
<!-- run xjc -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<executions>
<execution>
<id>xjc-generate_classes</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<packageName>test.jaxb.generated</packageName>
<schemaFiles>
root.xsd
</schemaFiles>
<schemaDirectory>${basedir}/src/main/resources/schemata</schemaDirectory>
<extension>true</extension>
<bindingDirectory>${basedir}/src/main/resources/bindings</bindingDirectory>
<outputDirectory>${basedir}/target/generated-sources/jaxb/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- overwrite created package-info.java -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<outputDirectory>${basedir}/target/generated-sources/jaxb/test/jaxb/generated</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/bindings</directory>
<include>package-info.java</include>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The problem is that you generate all your classes in one package (configured using the packageName of the Maven plugin.
Do not do this.
JAXB is somewhat based on the concept of package-namespace correspondence. There should be one package per namespace you use. While it is technically possible to do it otherwise, you'll be facing one problem after another. So it is better to follow this concept and use or generate one package per namespace. You can still configure target packages - but using the binding files instead of plugin configuration elements.

JAXB Code Inject into Enum Class

The background problem is when we reflect on a JAXB generated Enum class, toString() is called which without an #override of toString() will return .name() instead of .value(). So, I would like to inject my own toString().
I am unable to inject code into a JAXB generated Enum class. Although, I am able to inject code at the top level complexType and but not in the inline Enum class.
Here is the section of the XSD in question seen below (I have tried absolute and relative):
<jxb:bindings node="/xs:schema/xs:complexType[#name='QueryPgm']/xs:sequence/xs:element[#name='STATUS']/xs:simpleType">
I use these args:
"-verbose -Xinject-code -extension"
No errors appear and the output is:
parsing a schema...
compiling a schema...
[INFO] generating code
unknown location
com/ibm/query/pgm/ObjectFactory
com/ibm/query/pgm/QueryPgm
com/ibm/query/pgm/package-info
Here is the section of the schema in question:
<xs:complexType name="QueryPgm">
<xs:sequence>
<xs:element name="NAME" type="tns:nameOptions" minOccurs="1" maxOccurs="unbounded" />
<xs:element name="SHOW" minOccurs="0" maxOccurs="unbounded">
<xs:simpleType>
<xs:annotation>
<xs:appinfo>
<jxb:typesafeEnumClass name="showOptions"/>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="ALL" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="STATUS" minOccurs="0" maxOccurs="unbounded">
<xs:simpleType>
<xs:annotation>
<xs:appinfo>
<jxb:typesafeEnumClass name="statusOptions"/>
<jxb:bindings node="/xs:schema/xs:complexType[#name='QueryPgm']/xs:sequence/xs:element[#name='STATUS']/xs:simpleType">
<ci:code>
#Override
public String toString() { return this.value();}
</ci:code>
</jxb:bindings>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="DB-NOTAVL" />
<xs:enumeration value="IOPREV" />
<xs:enumeration value="LOCK" />
<xs:enumeration value="NOTINIT" />
<xs:enumeration value="STOSCHD" />
<xs:enumeration value="TRACE" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
I would appreciate help or ideas one might have. Thanks.
today is April 25th, 2019, Not sure if the author stills look for a
solution on this kind of issue after 5 years, anyway for whoever
cares, it works fine to inject code fragment into generated enum class
by jaxb( jvnet plugin). the reasoning is that we try to support xml
and json deserialization by legacy jaxb generated classes with only
xml annotations. so we don't really need json annotations by any maven
json plugins ( you can not apply both jaxb and json plugin to generate
classes with both json and xml annotations. would be a disaster). so
those legacy jaxb-generated java classes can be used for json string
deserialization ( response coming in). and enum name() and value() is
a pain. since jaxb has moved to another site with over 400+ issues
https://github.com/javaee/jaxb-v2 , most of which are not even
under active development or to be fixed soon. so I tried below to fix
the name() and value() issue, so when toString() of Enum instance is
called the 'real value' can be returned instead of the UPPERCASE
names. below are some code snippet and plugin information:
binder file:
<jaxb:bindings schemaLocation = "locale.xsd" node = "/xs:schema">
<jaxb:bindings node = "xs:simpleType[#name='localetype']">
<ci:code>
<![CDATA[
#Override
public String toString() {
return this.value();
}
]]>
</ci:code>
</jaxb:bindings>
</jaxb:bindings>
locale.xsd
<xs:simpleType name="localetype">
<xs:restriction base="xs:string">
<xs:enumeration value="en_US"/>
<xs:enumeration value="de_DE"/>
</xs:restriction>
</xs:simpleType>
main.xsd
<xs:element name="customLocale" type="localetype"/>
maven plugin
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.14.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/schema</schemaDirectory>
<bindingDirectory>src/main/resources/schema</bindingDirectory>
<schemaIncludes>
<include>*.xsd</include>
</schemaIncludes>
<forceRegenerate>true</forceRegenerate>
<removeOldOutput>true</removeOldOutput>
<verbose>true</verbose>
<extension>true</extension>
<args>
<arg>-Xinject-code</arg>
<arg>-extension</arg>
<arg>-XhashCode</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.4</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>0.6.4</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-default-value</artifactId>
<version>1.1</version>
</plugin>
</plugins>
</configuration>
</plugin>
jaxb class generated
#XmlType(name = "localetype", namespace = "http://www.xxxx.com/ns/datatype")
#XmlEnum
public enum Localetype {
#XmlEnumValue("en_US")
EN_US("en_US"),
#XmlEnumValue("de_DE")
DE_DE("de_DE"),
private final String value;
Localetype(String v) {
value = v;
}
public String value() {
return value;
}
public static Localetype fromValue(String v) {
for (Localetype c: Localetype.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
#Override
public String toString() {
return this.value();
}
}
jackson testing
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
jackson client code configuration.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
don't forget this:
READ_ENUMS_USING_TO_STRING as true ( jackson 2.x version )

Can't use jaxb bindings on individual xsd elements

I'm using jaxb to generate java source code from an xsd file.
I want to be able to specify which packages the sources are generated in on a per element basis, however whenever I generate sources I get the following error:
[ERROR] ****/src/main/xjb/common.xjb[8,24]
com.sun.istack.SAXParseException2: compiler was unable to honor this schemaBinding customization. It is attached to a wrong place, or its inconsistent with other bindings.
My bindings file common.xjb is attempting to place the element with the name (attribute value) 'api' in the package 'com.myxml.common.api':
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="../xsd/common/common.xsd" node="/xs:schema">
<jxb:bindings node="//xs:element[#name='api']">
<jxb:schemaBindings>
<jxb:package name="com.myxml.common.api" />
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
My xsd file common.xsd is:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.1" xml:lang="en">
<xs:element name='api'>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" />
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
And I'm using the following Maven plugin to get everything going:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>schema00-generate</id>
<phase>generate-sources</phase>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<schemaFiles>common/common.xsd</schemaFiles>
<bindingFiles>common.xjb</bindingFiles>
<bindingDirectory>${project.basedir}/src/main/xjb</bindingDirectory>
</configuration>
</execution>
</executions>
</plugin>
Why am I getting this error and how can I resolve it? I don't have any other bindings in use at this stage that I'm aware of.
Elements from the same namespace cannot be mapped to different packages so the package cannot be defined for anything other than the top level

jaxb doesn't generate enums with base integer

I have following xsd:
<xs:simpleType name="resultcode">
<xs:restriction base="xs:integer">
<xs:enumeration value="0" id="Approved_no_error">
<xs:annotation>
<xs:appinfo>
<jxb:typesafeEnumMember name="Approved_no_error"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
JAX-B just does nothing, no errors, no warnings just doesn't generate this class. If change base from xs:integer to xs:string then it's ok. But I need exactly integer values.
I generate classes with maven:
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>AuthGateway</id>
<goals>
<goal>xjc</goal>
</goals>
And question 2. JAX-B and IDE (IDEA) doesn't allow whitespaces in id attrribute. Why?
<xs:enumeration value="0" id="Approved_no_error"> - ok
<xs:enumeration value="0" id="Approved no error"> - not ok
Is it correct behaviour?
You can use an external binding file to get the behaviour that you are looking for:
JAXB enumeration with numeric values
http://blog.bdoughan.com/2011/08/jaxb-and-enums.html

Categories

Resources