JAXB - injecting code into a simpleType - jaxb

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.

Related

WSDL2Java: missing complex element type generates java.lang.Object argument types

I am trying to import this WSDL: https://gateway.monster.com:8443/bgwBroker
Among others, it includes this XSD: http://schemas.monster.com/current/xsd/Query.xsd, which contains this snippet:
<xsd:element name="Query">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Target" type="xsd:string"/>
<xsd:element name="SubTarget" type="xsd:string" minOccurs="0"/>
<xsd:element name="ResumeRestriction" minOccurs="0"/>
<xsd:element name="ReturnRestriction" minOccurs="0" maxOccurs="unbounded">
...
</xsd:element>
<xsd:element name="SelectBy" minOccurs="0" maxOccurs="unbounded">
...
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
...
<xsd:element name="ResumeRestriction">
...
</xsd:element>
As you can see, complex type ResumeRestriction and its fields is defined at the bottom, but referenced inside Query. There is a reference missing here. ReturnRestriction and SelectBy are defined inline and are generated correctly.
Using WSDL2Java, this generates the following annotated classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"target",
"subTarget",
"resumeRestriction",
"returnRestriction",
"selectBy"
})
#XmlRootElement(name = "Query")
public class Query {
#XmlElement(name = "Target", required = true)
protected String target;
#XmlElement(name = "SubTarget")
protected String subTarget;
#XmlElement(name = "ResumeRestriction")
protected Object resumeRestriction;
...
public void setResumeRestriction(Object value) {
this.resumeRestriction = value;
}
}
Making resumeRestriction of type Object instead of the right type.
If do have a generated version of ResumeRestriction just fine. They are just not being tied together:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"storeRenderedTextResume",
"doNotRenderSid",
"activeOnBoard"
})
#XmlRootElement(name = "ResumeRestriction")
public class ResumeRestriction {
...
}
If I now create a request using Spring Web Services, I cannot use the ResumeRestriction class, which I need in my request to set a specific flag.
ObjectFactory objectFactory = new ObjectFactory();
Query query = objectFactory.createQuery();
query.setTarget("JobSeekers");
ResumeRestriction resumeRestriction = objectFactory.createResumeRestriction();
resumeRestriction.setStoreRenderedTextResume(true);
query.setResumeRestriction(resumeRestriction);
getWebServiceTemplate().marshalSendAndReceive("https://gateway.monster.com:8443/bgwBroker", query);
This will throw the following error:
[com.sun.istack.SAXException2: Instance of "com.monster.schemas.monster.ResumeRestriction" is substituting "java.lang.Object", but "com.monster.schemas.monster.ResumeRestriction" is bound to an anonymous type.]
How can I solve this problem?
I obviously cannot change the WSDL or XSD, as I pull those in remotely. Is this is a bug on their side and if so, can I work around it?
You could specify the class reference in JAXB bindings file:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="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"
>
<jxb:bindings >
<jxb:globalBindings typesafeEnumMaxMembers="3000"/>
</jxb:bindings>
<jxb:bindings schemaLocation="http://schemas.monster.com/current/xsd/Query.xsd">
<jxb:bindings node="//xs:element[#name='Query']//xs:element[#name='ResumeRestriction']">
<jxb:class ref="com.monster.schemas.monster.ResumeRestriction"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>

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+++");

xjc not generating corresponding class member for <xsd:any>

Here is the part of schema that I am using:
<xsd:complexType name="ContentType" mixed="true">
<xsd:annotation>
<xsd:documentation><![CDATA[
The content type is a broad base type allowing any content.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="BaseContentType">
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"
/>
</xsd:sequence>
<xsd:attribute name="orientation" type="OrientationEnum" use="optional"
default="portrait">
<xsd:annotation>
<xsd:documentation><![CDATA[
The #orientation attribute is used to specify a "landscape"
orientation for the published form. This is primarily used
for schedules or for tables.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
And the binding file:
<jxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
version="2.1">
<jxb:bindings schemaLocation="../xsd/USLM-1.0.xsd">
<jxb:bindings
node="//xsd:group[#name='NoteStructure']">
<jxb:property name="NoteStructure3" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
And the xjc command to convert the schema to java objects:
xjc -d out -p test -b binding.xml schema.xsd
But the class generated for ContentType doesn't have class member for any. The generated class is below:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ContentType")
#XmlSeeAlso({
HeadingType.class,
NoteType.class,
QuotedContentType.class,
ColumnType.class,
PType.class
})
public class ContentType
extends BaseContentType
{
#XmlAttribute(name = "orientation")
protected OrientationEnum orientation;
/**
* Gets the value of the orientation property.
*
* #return
* possible object is
* {#link OrientationEnum }
*
*/
public OrientationEnum getOrientation() {
if (orientation == null) {
return OrientationEnum.PORTRAIT;
} else {
return orientation;
}
}
/**
* Sets the value of the orientation property.
*
* #param value
* allowed object is
* {#link OrientationEnum }
*
*/
public void setOrientation(OrientationEnum value) {
this.orientation = value;
}
}
What am I doing wrong?

Cast JAXB2 generated object to JAXBElement?

I have 2 sets of XSD's, one that generates RPC based calls, and another that defines the product specific methods. The RpcType object (generated by JAXB2) has a 'setRpcOperation' method defined by:
RpcType.setRpcOperation(JAXBElement<? extends RpcOperationType>)
That 'RpcOperation' object should be the 'specific product method' described above. One example is (also generated by JAXB2):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "get-user-stats", propOrder = {
"reset"
})
public class GetUserStats {
protected Boolean reset;
/**
* Gets the value of the reset property.
*
* #return
* possible object is
* {#link Boolean }
*
*/
public Boolean isReset() {
return reset;
}
/**
* Sets the value of the reset property.
*
* #param value
* allowed object is
* {#link Boolean }
*
*/
public void setReset(Boolean value) {
this.reset = value;
}
}
Now, is it possible to create an instance of 'GetUserStatus' and add it to the RpcType object via setRpcOperation?
This type of scenario is common:
One schema to represent the message
Multiple schemas to represent the payload.
Below is one way this could be done:
Message Schema - message.xsd
Have one XML schema to represent your message envelope. Introduce one type to represent the body of the message. This type will be extended by the different payloads.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/message"
xmlns="http://www.example.org/message"
elementFormDefault="qualified">
<xsd:element name="message">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="body" type="body"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="body">
</xsd:complexType>
</xsd:schema>
Payload Schema - customer.xsd
This schema corresponds to a specific type of message payload. Notice how the customer type extends the body type from the message schema.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://www.example.org/customer"
xmlns="http://www.example.org/customer"
xmlns:m="http://www.example.org/message"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:import schemaLocation="message.xsd" namespace="http://www.example.org/message"/>
<xsd:complexType name="customer">
<xsd:complexContent>
<xsd:extension base="m:body">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
org.example.message.package-info
This class was generated from message.xsd.
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/message", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.message;
org.example.message.Message
This class was generated from message.xsd.
package org.example.message;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"body"
})
#XmlRootElement(name = "message")
public class Message {
#XmlElement(required = true)
protected Body body;
public Body getBody() {
return body;
}
public void setBody(Body value) {
this.body = value;
}
}
org.example.message.Body
This class was generated from message.xsd.
package org.example.message;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "body")
public class Body {
}
org.example.customer.package-info
This class was generated from customer.xsd.
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/customer", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.customer;
org.example.customer.Customer
This class was generated from customer.xsd.
package org.example.customer;
import javax.xml.bind.annotation.*;
import org.example.message.Body;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "customer", propOrder = {
"name"
})
public class Customer extends Body {
#XmlElement(required = true)
protected String name;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
}
Demo Class
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.example.customer.*;
import org.example.message.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Message.class, Customer.class);
Message message = new Message();
Customer customer = new Customer();
customer.setName("Jane Doe");
message.setBody(customer);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(message, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message xmlns="http://www.example.org/message" xmlns:ns2="http://www.example.org/customer">
<body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:customer">
<ns2:name>Jane Doe</ns2:name>
</body>
</message>
EDIT #1
In response to your second question (Cast JAXB2 generated object to JAXBElement?)
I don't see where the JAXBElement comes into play with this example. I am able to run the following code:
import generated.GetFailedLoginCount;
import ietf.params.xml.ns.netconf.base._1.RpcType;
public class Demo {
public static void main(String[] args) {
RpcType rpc = new RpcType();
rpc.setMessageId("123");
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpc.setRpcOperation(rpcOperation);
}
}
EDIT #2
After changing the import to import to http://www.iana.org/assignments/xml-registry/schema/netconf.xsd I'm seeing the same behaviour as you.
To set the property correctly you will need to do something like:
RpcType rpc = new RpcType();
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpcOperation.setReset(true);
JAXBElement<GetFailedLoginCount> rpcOperationJE = new JAXBElement(new QName("foo"), GetFailedLoginCount.class, rpcOperation);
rpc.setRpcOperation(rpcOperationJE);
JAXBElement supplies the element name for the GetFailedLoginCount value. This is required because the element corresponding to the rpcOperation property is substitutable:
<xs:element name="get-config" type="getConfigType" substitutionGroup="rpcOperation" />
In your schema that imports netconf.xsd you should have an element of type "get-failed-login-count" that can be substituted for "rpcOperation". This will be supplied as a QName to the JAXBElement. Since we used element name "foo" above the schema update would look like:
<xs:element name="foo" type="get-failed-login-count" substitutionGroup="rpcOperation" />
Ok, so here is a subset of what I am trying to do. The above example was extremely helpful, but I still am not able to create a JAXBElement:
Base envelope can be found: http://www.iana.org/assignments/xml-registry/schema/netconf.xsd
Payload for rpcOperationType (I added the ** lines):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dmi="http://xml.juniper.net/dmi"
** xmlns:netconf="urn:ietf:params:xml:ns:netconf:base:1.0"
>
**<xs:import schemaLocation="netconf.xsd" namespace="urn:ietf:params:xml:ns:netconf:base:1.0"/>
<!-- get-failed-login-count -->
<xs:complexType name="get-failed-login-count">
**<xs:complexContent>
** <xs:extension base="netconf:rpcOperationType">
<xs:annotation>
<xs:appinfo>
<dmi:rpc-info>
<name>Get failed login count for Authentication failure and Exceeded user</name>
<description>
This command returns the Number of Logins refused due to exceeding allowed limits and Auth failure (24 hour moving window)
</description>
<rpc-reply-tag>failed-login-count</rpc-reply-tag>
</dmi:rpc-info>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="reset" type="xs:boolean" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<dmi:param-info>
<name>Reset Stats</name>
<description>
This will govern the reseting of this statistics data. By default, the data is not reset.
</description>
</dmi:param-info>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
** </xs:extension>
**</xs:complexContent>
</xs:complexType>
Now, the generated GetFailedLogin class extends RpcOperationType, but I am not sure how to set it in the RpcType object:
RpcType rpc = new RpcType();
rpc.setMessageId("123");
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpc.setRpcOperation(); // Expects JAXBElement<? Extends RpcOperationType>

Resources