XSD class generation using XJC produces dead code for Boolean values - xsd

I have the following XDS that represents various metadata item types:
<xs:simpleType name="BooleanTypeKey">
<xs:restriction base="xs:string">
<xs:enumeration value="isValue1" />
<xs:enumeration value="isValue2" />
<xs:enumeration value="isValue3" />
</xs:restriction>
</xs:simpleType>
<xs:complexType name="BooleanType">
<xs:simpleContent>
<xs:extension base="xs:boolean">
<xs:attribute name="key" type="BooleanTypeKey" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Using the following xjc to produce my classes:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>myId</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<packageName>com.myorg.packagename.model</packageName>
<schemaDirectory>/src/main/resources/xsd</schemaDirectory>
<bindingDirectory>/src/main/resources/xjb</bindingDirectory>
<outputDirectory>${project.build.directory}/generated/jaxb</outputDirectory>
<extension>true</extension>
<enableIntrospection>true</enableIntrospection>
<arguments>-Xequals -xhasCode -xtoString</arguments>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.4</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
This produces the following class for the BooleanType object:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "BooleanType", propOrder = {
"value"
})
public class BooleanType implements Equals, HashCode, ToString
{
#XmlValue
protected Boolean value;
#XmlAttribute(name = "key", required = true)
protected BooleanTypeKey key;
//... getters and setters ...
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
//... basic object checks ...
final BooleanType that = ((BooleanType) object);
{
// This is NOT part of the generated code
// Why does the next 2 lines look like they do??? It should only read:
// boolean lhsValue = this.isValue();
// The fact that there is a check for *true*
// (constant value check... really???)
// Not only is this completely useless, but it causes dead code production (the else part (false)).
boolean lhsValue;
lhsValue = (true?this.isValue():false);
boolean rhsValue;
rhsValue = (true?that.isValue():false);
//...more code ...
}
//...more code ...
}
}
Can someone tell me if I can avoid producing such code, I am using a faulty version of xjc? A version that is too old?
Thanks,

Related

Generate XML schema from Kotlin Enum using Jaxb

I would like to use some XML schema files from Kotlin enum classes.
When I generate classes from an xml schema, this is the output:
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for LogLevelType.
*
* <p>The following schema fragment specifies the expected content contained within this class.
* <p>
* <pre>
* <simpleType name="LogLevelType">
* <restriction base="{http://www.w3.org/2001/XMLSchema}string">
* <enumeration value="ERROR"/>
* <enumeration value="WARNING"/>
* <enumeration value="INFO"/>
* <enumeration value="DEBUG"/>
* </restriction>
* </simpleType>
* </pre>
*
*/
#XmlType(name = "LogLevelType", namespace = "http://www.brabantia.com/XMLSchema/Logging")
#XmlEnum
public enum LogLevelType {
ERROR,
WARNING,
INFO,
DEBUG;
public String value() {
return name();
}
public static LogLevelType fromValue(String v) {
return valueOf(v);
}
}
So I figured that when I would create an enum class and add the same annotations, I would be able to do the same in reverse.
import javax.xml.bind.annotation.XmlEnum
import javax.xml.bind.annotation.XmlType
#XmlType(name = "ErrorCategoryType", namespace = "http://www.brabantia.com/XMLSchema/Enum")
#XmlEnum
enum class ErrorCategoryType {
FUNCTIONAL,
TECHNICAL;
fun value(): String = name
fun fromValue(v: String) = valueOf(v)
}
In my pom file I have the following configuration:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources/jaxb</outputDirectory>
<!-- The package of your generated sources -->
<packageName>com.brabantia.common.schema</packageName>
<sources>
<source>${project.basedir}/src/main/resources/BrabantiaMain.xsd</source>
</sources>
</configuration>
</execution>
<execution>
<id>schemagen</id>
<goals>
<goal>schemagen</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/src/main/resources/Generated</outputDirectory>
<sources>
<source>${project.basedir}/src/main/kotlin/com/brabantia/common/xmlschemas/enums</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
The Java classes are generated using xjc, but when I try to generate the xml schemas using schemagen, the following error is displayed:
Failed to execute goal org.codehaus.mojo:jaxb2-maven-plugin:2.3.1:schemagen (default-cli) on project xml-schemas: Execution default-cli of goal org.codehaus.mojo:jaxb2-maven-plugin:2.3.1:schemagen failed: syntax error #[1,41] in file:/C:/projects/INTEGRATION_FACTORY/XML_SCHEMAS/src/main/kotlin/com/brabantia/common/xmlschemas/enum/ErrorCategoryType.kt -> [Help 1]
How can I generate the XML schemas from the Kotlin enum classes?

ObjectMapper throws exception: "no single-String constructor/factory method", due to "nillable" attribute? What can be done?

I need help to solve/fix the cause of the following exception...
i.e.,
Can not instantiate value of type [simple type, class javax.xml.bind.JAXBElement<javax.xml.datatype.XMLGregorianCalendar>]
from String value ('2018-02-04');
no single-String constructor/factory method
This is the json string in question
i.e.,
{"MySubGroup":[{"MyDateTime":"2018-02-01T01:01:01.001-05:00","MyDate":"2018-02-04T01:01:01.001-05:00"}]}
The schema element that is causing the parsing to fail looks like this...
i.e.,
<xs:element name="MyDate" type="xs:date" minOccurs="0" nillable="true"/>
(PLEASE NOTE: if I remove "nillable" attribute from MyDate schema element, the example runs without issues)
QUESTION:
--How can I overcome this issue *without* removing this "nillable" attribute?
This is the schema...
i.e.,
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://aaa.bbb.ccc"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:es="http://aaa.bbb.ccc"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="MySubGroupType">
<xs:all>
<xs:element name="MyDateTime" type="xs:dateTime" minOccurs="0" />
<xs:element name="MyDate" type="xs:date" minOccurs="0" nillable="true"/>
</xs:all>
</xs:complexType>
<xs:element name="MyGroup">
<xs:complexType>
<xs:sequence>
<xs:element name="MySubGroup" type="es:MySubGroupType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This is the code in question...
i.e.,
String jsonString = "{\"MySubGroup\":[{\"MyDateTime\":\"2018-02-01T01:01:01.001-05:00\",\"MyDate\":\"2018-02-04\"}]}";
om = new ObjectMapper();
om.findAndRegisterModules();
om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); // (NOTE: PropertyNamingStrategy.UPPER_CASE is not available in jackson 2.6.3)
mg = om.readValue(jsonString, MyGroup.class);
MySubGroupType sgt = mg.getMySubGroup().get(0);
System.out.println("value of MyDate element is:" + sgt.getMyDate());
The Exception occurs on this statement...
i.e.,
mg = om.readValue(jsonString, MyGroup.class);
More details below, if needed...
MyRoute.java...
i.e,
package aaa.bbb.ccc.jar;
import aaa.bbb.ccc.generated.MyGroup;
import aaa.bbb.ccc.generated.MySubGroupType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.cdi.ContextName;
#ContextName("rest-dsl")
public class MyRoutes extends RouteBuilder {
public MyRoutes() {
}
private ObjectMapper om = new ObjectMapper();
private MyGroup mg;
#Override
public void configure() throws Exception {
org.apache.log4j.MDC.put("app.name", "testjsonparse");
from("timer://foo?fixedRate=true&repeatCount=1")
.setBody(constant("placeholder"))
.to("seda:node1");
from("seda:node1")
.process(new Processor() {
#Override
public void process(Exchange exchange) {
try {
String jsonString = "{\"MySubGroup\":[{\"MyDateTime\":\"2018-02-01T01:01:01.001-05:00\",\"MyDate\":\"2018-02-04\"}]}";
om = new ObjectMapper();
om.findAndRegisterModules();
om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); //not available in jackson 2.6.3: PropertyNamingStrategy.UPPER_CASE);
mg = om.readValue(jsonString, MyGroup.class);
MySubGroupType sgt = mg.getMySubGroup().get(0);
exchange.getIn().setBody("+++success+++");
} catch (Exception e) {
e.printStackTrace();
exchange.getIn().setBody("---failure---");
}
}
})
.to("seda:node2");
from("seda:node2")
.log("\n\n... ${body}");
}
}
PreservePropertyNameStrategy.java...
i.e.,
package aaa.bbb.ccc.jar;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
// the myschema.xml schema (for academic reasons) capitalizes the 1st letter of each property name...
//...we handle the issue by extending/customizing PropertyNamingStrategy - mainly because the option "PropertyNamingStrategy.UPPER_CASE" is not yet available in jackson 2.6.3 (?)...
public class PreservePropertyNameStrategy extends PropertyNamingStrategy {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
String m = method.getName();
return (m.startsWith("is")?m.substring(2):m.substring(3));
}
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return method.getName().substring(3);
}
}
MySubGroupType.java - generated from the schema...
i.e.,
package aaa.bbb.ccc.generated;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.datatype.XMLGregorianCalendar;
/**
* <p>Java class for MySubGroupType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="MySubGroupType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <all>
* <element name="MyDateTime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
* <element name="MyDate" type="{http://www.w3.org/2001/XMLSchema}date" minOccurs="0"/>
* </all>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MySubGroupType", propOrder = {
})
public class MySubGroupType {
#XmlElement(name = "MyDateTime")
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar myDateTime;
#XmlElementRef(name = "MyDate", namespace = "http://aaa.bbb.ccc", type = JAXBElement.class, required = false)
protected JAXBElement<XMLGregorianCalendar> myDate;
/**
* Gets the value of the myDateTime property.
*
* #return
* possible object is
* {#link XMLGregorianCalendar }
*
*/
public XMLGregorianCalendar getMyDateTime() {
return myDateTime;
}
/**
* Sets the value of the myDateTime property.
*
* #param value
* allowed object is
* {#link XMLGregorianCalendar }
*
*/
public void setMyDateTime(XMLGregorianCalendar value) {
this.myDateTime = value;
}
/**
* Gets the value of the myDate property.
*
* #return
* possible object is
* {#link JAXBElement }{#code <}{#link XMLGregorianCalendar }{#code >}
*
*/
public JAXBElement<XMLGregorianCalendar> getMyDate() {
return myDate;
}
/**
* Sets the value of the myDate property.
*
* #param value
* allowed object is
* {#link JAXBElement }{#code <}{#link XMLGregorianCalendar }{#code >}
*
*/
public void setMyDate(JAXBElement<XMLGregorianCalendar> value) {
this.myDate = value;
}
}
MyGroup.java - generated from the schema...
i.e.,
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2018.02.08 at 05:44:17 PM EST
//
package aaa.bbb.ccc.generated;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="MySubGroup" type="{http://aaa.bbb.ccc}MySubGroupType" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"mySubGroup"
})
#XmlRootElement(name = "MyGroup")
public class MyGroup {
#XmlElement(name = "MySubGroup")
protected List<MySubGroupType> mySubGroup;
/**
* Gets the value of the mySubGroup property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the mySubGroup property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getMySubGroup().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {#link MySubGroupType }
*
*
*/
public List<MySubGroupType> getMySubGroup() {
if (mySubGroup == null) {
mySubGroup = new ArrayList<MySubGroupType>();
}
return this.mySubGroup;
}
}
This is the pom.xml...
i.e.,
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>aaa.bbb.ccc</groupId>
<artifactId>testjsonissue</artifactId>
<version>1.0.0</version>
<packaging>bundle</packaging>
<name>testjsonissue</name>
<description>testjsonissue</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skipTests>true</skipTests>
<mq.version>8.0.0.7</mq.version>
<timestamp>v${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyyMMdd.HHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.17.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cdi</artifactId>
<version>2.17.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>2.17.0</version>
<scope>provided</scope>
</dependency>
<!-- version to use, as per: https://mvnrepository.com/artifact/org.apache.camel/camel-jackson/2.17.0.redhat-630283 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.3</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/resources/xsd/myschema.xsd</source>
</sources>
<packageName>aaa.bbb.ccc.generated</packageName>
<verbose default-value="false">${xjc.verbose}</verbose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.3.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Export-Package>aaa.bbb.ccc*</Export-Package>
<Bundle-Version>${project.version}-${timestamp}</Bundle-Version>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
**Environment... I'm confined to these dependencies/versions, etc **
i.e.,
Java 8
Jboss Fuse, v6.3.0
camel-jackson, v2.17.0
jackson-databind, v2.6.3
jackson-datatype-jsr310, v2.6.3
Apparently, was missing the following instruction...
om.registerModule(new JavaTimeModule());
...now works...
in otherwords, this
String jsonString = "{\"MySubGroup\":[{\"MyDateTime\":\"2018-02-01T01:01:01.001-05:00\",\"MyDate\":\"2018-02-04\"}]}";
om = new ObjectMapper();
om.findAndRegisterModules();
om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); //not available in jackson 2.6.3: PropertyNamingStrategy.UPPER_CASE);
mg = om.readValue(jsonString, MyGroup.class);
MySubGroupType sgt = mg.getMySubGroup().get(0);
exchange.getIn().setBody("+++success+++");
...is changed to this...
String jsonString = "{\"MySubGroup\":[{\"MyDateTime\":\"2018-02-01T01:01:01.001-05:00\",\"MyDate\":\"2018-02-04\"}]}";
om = new ObjectMapper();
om.registerModule(new JavaTimeModule()); //<=== changed
om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); //not available in jackson 2.6.3: PropertyNamingStrategy.UPPER_CASE);
mg = om.readValue(jsonString, MyGroup.class);
MySubGroupType sgt = mg.getMySubGroup().get(0);
exchange.getIn().setBody("+++success+++");

JAXB - injecting code into a simpleType

I am trying to find out how to inject a code into a xsd simpleType that is an ennumeration.
My XSD is just like below inside commons.xsd
<xsd:simpleType name="tPessoa">
<xsd:annotation>
<xsd:documentation>Enumeracao que descreve se e uma pessoa fisica ou
juridica
Valores possiveis:
- pf: para PESSOA FiSICA;
- pj: para PESSOA
JURiDICA.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="pf" />
<xsd:enumeration value="pj" />
</xsd:restriction>
</xsd:simpleType>
My binding is just like below
<jxb:bindings schemaLocation="../src/main/resources/commons.xsd"
node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="my.canonical.commons" />
</jxb:schemaBindings>
<jxb:bindings node="/xsd:schema/xsd:simpleType[#name='tPessoa']">
<ci:code>
public static TPessoa fromValue(String v) {
if(("F".equalsIgnoreCase(v)) || ("PF".equalsIgnoreCase(v))) return PF;
if(("J".equalsIgnoreCase(v)) || ("PJ".equalsIgnoreCase(v))) return PJ;
throw new IllegalArgumentException(v);
}
</ci:code>
</jxb:bindings>
</jxb:bindings>
And I am passing inside the maven plugin the argument -Xinject-code-extension
But the result observed does not changes.
I read some articles here in StackOverflow but it is unclear to me if this is a limitation of JAXB or if I am missing something.
My idea is to generate a class just like below
#XmlType(name = "tPessoa")
#XmlEnum
public enum TPessoa {
#XmlEnumValue("pf")
PF("pf"),
#XmlEnumValue("pj")
PJ("pj");
private final String value;
TPessoa(String v) {
value = v;
}
public String value() {
return value;
}
public static TPessoa fromValue(String v) {
if(("F".equalsIgnoreCase(v)) || ("PF".equalsIgnoreCase(v))) return PF;
if(("J".equalsIgnoreCase(v)) || ("PJ".equalsIgnoreCase(v))) return PJ;
throw new IllegalArgumentException(v);
}
}
Because F and PF are synonyms and some underlying systems returns different values for the same entity, some of them returns F others PF and the same behavior for J and PJ.
How to do it? Is it Possible?
I have never managed to inject code into enumerations in JAXB. I could only inject code into complexTypes.
Below you can find an alternative example which injects the fromValue method from your question into a complex type and might be useful as well.
Maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fernandes</groupId>
<artifactId>jaxb-test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<extension>true</extension>
<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
<bindingDirectory>${basedir}/src/main/xjb</bindingDirectory>
<generatePackage>com.fernandes.jaxb</generatePackage>
<args>
<arg>-Xinject-code</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>1.11.1</version>
</plugin>
</plugins>
</configuration>
</plugin>
</plugins>
</build>
</project>
Schema
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://xmlns.tui.com/int/customer360/cdm/customer/v1"
targetNamespace="http://xmlns.tui.com/int/customer360/cdm/customer/v1"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:complexType name="pessoaType">
<xsd:sequence>
<xsd:element name="type" type="tPessoa"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="tPessoa">
<xsd:annotation>
<xsd:documentation>Enumeracao que descreve se e uma pessoa fisica ou
juridica
Valores possiveis:
- pf: para PESSOA FiSICA;
- pj: para PESSOA
JURiDICA.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="pf"/>
<xsd:enumeration value="pj"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Binding file
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:ci="http://jaxb.dev.java.net/plugin/code-injector">
<jxb:bindings schemaLocation="../xsd/schema.xsd">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
<jxb:bindings node="/xsd:schema/xsd:complexType[#name='pessoaType']">
<ci:code>
<![CDATA[
public static TPessoa fromValue(String v) {
if(("F".equalsIgnoreCase(v)) || ("PF".equalsIgnoreCase(v))) return TPessoa.PF;
if(("J".equalsIgnoreCase(v)) || ("PJ".equalsIgnoreCase(v))) return TPessoa.PJ;
throw new IllegalArgumentException(v);
}
]]>
</ci:code>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
If you run maven with:
mvn clean package
You will generate the TPessoa class and a PessoaType. The latter will contain the static method you specified.
PessoaType
package com.fernandes.jaxb;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for pessoaType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="pessoaType">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="type" type="{http://xmlns.tui.com/int/customer360/cdm/customer/v1}tPessoa"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "pessoaType", propOrder = {
"type"
})
public class PessoaType {
#XmlElement(required = true)
#XmlSchemaType(name = "string")
protected TPessoa type;
/**
* Gets the value of the type property.
*
* #return
* possible object is
* {#link TPessoa }
*
*/
public TPessoa getType() {
return type;
}
/**
* Sets the value of the type property.
*
* #param value
* allowed object is
* {#link TPessoa }
*
*/
public void setType(TPessoa value) {
this.type = value;
}
public static TPessoa fromValue(String v) {
if(("F".equalsIgnoreCase(v)) || ("PF".equalsIgnoreCase(v))) return TPessoa.PF;
if(("J".equalsIgnoreCase(v)) || ("PJ".equalsIgnoreCase(v))) return TPessoa.PJ;
throw new IllegalArgumentException(v);
}
}
This is not 100% what you want, but it is pretty close.

What is default namespace for public enum type?

I have a class which contains inner enum type.
#XmlRootElement
public class Address {
#XmlEnum
#XmlType(name="addressType")
public static enum Type {
}
}
Here is my package-info.java.
#XmlSchema(
attributeFormDefault = XmlNsForm.UNQUALIFIED,
elementFormDefault = XmlNsForm.QUALIFIED,
namespace = "http://some",
xmlns = {
#XmlNs(prefix = "xsi",
namespaceURI = XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
}
) #XmlAccessorType(XmlAccessType.NONE)
package some;
It works find when I use JAXBContex#generateSchema.
But org.codehaus.mojo:jaxb2-maven-plugin:schemagen generates separate schemas.
One for address which has a namespace,
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="..."
targetNamespace="...">
<xs:complexType name="address">
...
<xs:sequence>
...
<xs:element name="type" type="addressType"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
and the other for addressType which has no namespace.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xs:simpleType name="addressType">
<xs:restriction base="xs:string">
<xs:enumeration value="CC"/>
<xs:enumeration value="BCC"/>
<xs:enumeration value="TO"/>
<xs:enumeration value="REPLY_TO"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Which one is right?
The XML schema generator schemagen which comes along with JAXB (and JDK) generates two .xsd files from class Address (as shown), very much like the ones you have posted as output from the maven plugin. However, the first .xsd file contains
<xs:import schemaLocation="schema2.xsd"/>
which is not in your first .xsd. Did you remove this element? With this element, there is no reason to doubt the pair of .xsd files.
It would have been nice to see the single .xsd file.
You can also use xjc to generate Java classes from the .xsd files and compare the results.

Custom JAXB Binding Causes Namespace Error

History
I am generating Java classes from a schema not under my control. I am exporting it to a jar that is a dependency for a web service project. This works correctly. I attempted to add a custom binding to marshal and unmarshal xs:date and xs:dateTime as instances of org.joda.DateTime instead of XMLGregorianCalendar. I am able to generate the jar, compile it within the webservice, and deploy without issue. Once deployed however, the XML requests that previously worked, now throw the following exception:
unexpected element (uri:"", local:"ElementName"). Expected elements are <{schemaNamespace}ElementName>
This exception does not occur at the root element. Several earlier instances of xs:date and xs:dateTime are parsed without issue, the exception first appears on a complex type that contains an xs:date.
Here's an example of the XML structure:
<soap:Envelope xmlns:ns="webServiceNamespace">
<soap:Body>
<request>
<root>
<child1>
<Date /> <--Works fine.
<childList>
<childListElement> <-- Exception thrown on this element.
<Date />
</childListElement>
</childList>
</child1>
</root>
</request>
</soap:Body>
</soap:Envelope>
The webServiceNamespace and schemaNamespace are different, but previously only the one was required in the soap envelope.
Question
Why, after adding a custom binding, is the parser asking me to put a namespace on only a handful of parent elements who have a child affected by the custom binding ?
BindingAdapter
package myPackage;
#XmlTransient
public class JodaDateTimeAdapter extends XmlAdapter<String, DateTime> {
private static final DateTimeFormatter XML_DATE_FORMAT = ISODateTimeFormat.dateTimeNoMillis();
#Override
public DateTime unmarshal(String date) throws Exception {
return XML_DATE_FORMAT.parseDateTime(date);
}
#Override
public String marshal(DateTime dateTime) throws Exception {
return XML_DATE_FORMAT.print(dateTime);
}
}
Binding.xjb
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="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"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
jaxb:extensionBindingPrefixes="xjc"
version="2.1" >
<jaxb:globalBindings>
<xjc:javaType name="org.joda.time.DateTime" xmlType="xs:dateTime" adapter="myPackage.JodaDateTimeAdapter" />
<xjc:javaType name="org.joda.time.DateTime" xmlType="xs:date" adapter="myPackage.JodaDateAdapter" />
</jaxb:globalBindings>
</jaxb:bindings>
POM.xml(relevant bits anyway)
<project>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
...
<execution>
<id>generateSchema</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<packageName>myPackage</packageName>
...
<extension>true</extension>
<arguments>-no-header -Xxew</arguments>
<bindingDirectory>src/main/bindings</bindingDirectory>
<bindingFiles>JodaBinding.xjb</bindingFiles>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.github.jaxb-xew-plugin</groupId>
<artifactId>jaxb-xew-plugin</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Comments
I want to stress that this works perfectly fine without the binding, as far as I can tell the generated class files are identical (except for the extra annotations specific to wrappers). The xml used in the SOAP request is valid for the WSDL generated by the web service, and the WSDL is the same whether or not I use a custom binding. Only elements who have are a member of a collection and have a child with a date require the schema namespace. Lastly, once I provide the namespaces in my request, the response puts the request object in the webServiceNamespace and all the children other than the schema-defined root in the schemaNamespace. Previously the entire response was in the webServiceNamespace.
Clearly the addition of the custom binding is doing something wonky (technical term) with the namespace resolution, but I'm not well versed enough in the topic to make any headway.
Suggestions ?
Update: Removing the XEW plugin for pretty-collections generation did not affect this issue.
Update: This is an example of a class containing a date before the binding and after. This is the only property to change:
Before
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "QuestionAnswerType", propOrder = {
"question",
"answer",
"questionDate"
})
public class QuestionAnswerType {
#XmlElement(name = "Question")
protected String question;
#XmlElement(name = "Answer")
protected String answer;
#XmlElement(name = "QuestionDate")
#XmlSchemaType(name = "date")
protected XMLGregorianCalendar questionDate;
...
After
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "QuestionAnswerType", propOrder = {
"question",
"answer",
"questionDate"
})
public class QuestionAnswerType {
#XmlElement(name = "Question")
protected String question;
#XmlElement(name = "Answer")
protected String answer;
#XmlElement(name = "QuestionDate", type = String.class)
#XmlJavaTypeAdapter(JodaDateAdapter.class)
#XmlSchemaType(name = "date")
protected DateTime questionDate;
...
Update: This works without issue if I execute the build against a schema with no namespace. Obviously not the fix, but a workaround for now.

Resources