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?
Related
Trying to re-partition my dataframe in order to achieve parallelism. It was suggested to each partition size should be less than 128MB , in-order to achieve it I need to calculate how much the size of each row in my dataframe. So how to calculate/find how much each row size in my dataframe?
Thank you.
As discussed in the link that I have mentionned in my first comment, you can use java.lang.instrument
The solution that I propose is in Java, Maven and with Spark 2.4.0
You must have the following structure, otherwise you will have to adapt your pom.xml to your structure:
src
--main
----java
------size
--------Sizeof.java
------spark
--------SparkJavaTest.java
----resources
------META-INF
--------MANIFEST.MF
pom.xml
<?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.formation.SizeOf</groupId>
<artifactId>SizeOf</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifestFile>
src/main/resources/META-INF/MANIFEST.MF
</manifestFile>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>
spark.SparkJavaTest
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
</project>
Sizeof
package size;
import java.lang.instrument.Instrumentation;
final public class Sizeof {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}
public static long sizeof(Object o) {
return instrumentation.getObjectSize(o);
}
}
SparkJavaTest
package spark;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import size.Sizeof;
public class SparkJavaTest {
public static SparkSession spark = SparkSession
.builder()
.appName("JavaSparkTest")
.master("local")
.getOrCreate();
public static void main(String[] args) {
Dataset<Row> ds = spark.read().option("header",true).csv("sample.csv");
ds.show(false);
// Get the size of a Dataset
System.out.println("size of ds " + Sizeof.sizeof(ds));
JavaRDD dsToJavaRDD = ds.toJavaRDD();
// Get the size of a JavaRDD
System.out.println("size of rdd" + Sizeof.sizeof(dsToJavaRDD));
}
}
MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: size.Sizeof
Main-Class: spark.SparkJavaTest
After that, you clean and package :
mvn clean package
Then you can run and get the size of your objects:
java -javaagent:target/SizeOf-1.0-SNAPSHOT-jar-with-dependencies.jar -jar target/SizeOf-1.0-SNAPSHOT-jar-with-dependencies.jar
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+++");
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.
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,
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.