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
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'm doing a conversion from maven to gradle,
the project I'm converting is currently using the maven plugin:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.11.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/schema</schemaDirectory>
</configuration>
</plugin>
the following element generates a SomeClass.class file in the target dir:
<xs:element name="SomeClass" type="SomeClassType">
<xs:annotation>
<xs:appinfo>
<meta:content-type>
application/xml;application/json;class=com.example
</meta:content-type>
</xs:appinfo>
<xs:documentation source="since">5.7</xs:documentation>
<xs:documentation xml:lang="en">
...
</xs:documentation>
</xs:annotation>
</xs:element>
For gradle I went for this plugin: https://github.com/jacobono/gradle-jaxb-plugin
which generates source files instead of .class files, which is fine, but it does not generate a class for that specific element
jaxb {
xsdDir = "${projectDir.path - rootDir.path}/src/main/resources/schema"
episodesDir = "${buildDir.path - rootDir.path}/schema/episodes"
xjc {
destinationDir = jaxbDstDir
producesDir = jaxbDstDir
}
}
with:
jaxb 'com.sun.xml.bind:jaxb-core:2.2.11'
jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.11'
jaxb 'com.sun.xml.bind:jaxb-impl:2.2.11'
the dependencies are the same as the maven plugin is using,
other classes are generated okay
Any ideas why?
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 )
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 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