I used Jaxb to generate a Jar file from xsd:
CustomObject inputRequest = xmlMapper.readValue(input, CustomObject.class);
The error message I am getting is:
com.fasterxml.jackson.databind.JsonMappingException: Multiple fields
representing property "PS": OrderLineType#pS vs OrderLineType#pSV5 at
[Source: (StringReader); line: 1, column: 1]
And my class is:
#XmlElement(name = "PS", namespace = "financetypes:defn:v4")
protected financetypes.v4.PSType pS;
#XmlElement(name = "PS", namespace = "financetypes:defn:v5")
protected financetypes.v5.PSType pSV5;
They have the same name, but different namespace.
Is xmlmapper able to handle XmlElement that has the same name and different namespace?
If yes, how do I fix this? If no, what should I do?
I am building jar file from jenkin. Is there a plugin that I can use to fix this issue?
Thanks!
here is my xsd
v4.xsd
<!--Begin Definition: Complex Type: PriceStructureType-->
<xs:complexType name="PriceStructureType">
<xs:sequence>
<xs:element name="PriceModel" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
TODO: Add valid items...
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element ref="finance:SourceSystemPrice" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ComponentPrice" type="finance:ComponentListType" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="PriceStructure" type="finance:PriceStructureType"/>
<!--End Definition: Complex Type: PriceStructureType-->
v5.xsd
<!--Begin Definition: Complex Type: PriceStructureType-->
<xs:complexType name="PriceStructureType">
<xs:sequence>
<xs:element name="PriceModel" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
TODO: Add valid items...
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element ref="finance:SourceSystemPrice" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ComponentPrice" type="finance:ComponentListType" minOccurs="0">
<xs:annotation>
<xs:documentation>
Will be required in future...
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="PriceStructure" type="finance:PriceStructureType"/>
<!--End Definition: Complex Type: PriceStructureType-->
common.xsd
xmlns:finance="urn:financetypes:defn:v4"
xmlns:finance_v5="urn:financetypes:defn:v5"
<xs:import namespace="urn:financetypes:defn:v4" schemaLocation="financetypes.v4.xsd"/>
<xs:import namespace="urn:financetypes:defn:v5" schemaLocation="financetypes.v5.xsd"/>
<xs:choice>
<xs:element ref="finance:PriceStructure" minOccurs="0">
<xs:annotation>
<xs:documentation xml:lang="en">
Price Structure itemizes the price components of this OrderLine. Pricing
is a integral part of the Sales Order record.
This should be a required element for a sales order, but it is marked
as optional for backward compatibility.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element ref="finance_v5:PriceStructure" minOccurs="0">
<xs:annotation>
<xs:documentation xml:lang="en">
Price Structure itemizes the price components of this OrderLine. Pricing
is a integral part of the Sales Order record.
This should be a required element for a sales order, but it is marked
as optional for backward compatibility.
</xs:documentation>
<xs:appinfo>
<jaxb:property name="PriceStructureV5"/>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:choice>
You could do this. For a root class containing these 2 elements:
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name = "PS", namespace = "financetypes:defn:v4")
protected financetypes.v4.PSType pS;
#XmlElement(name = "PS", namespace = "financetypes:defn:v5")
protected financetypes.v5.PSType pSV5;
}
You can create you classes with the different versions like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "v4PS", namespace = "financetypes:defn:v4")
public class PSType {
#XmlValue
private String value;
}
and:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "v5PS", namespace = "financetypes:defn:v5")
public class PSType {
#XmlValue
private String value;
}
For a sample xml as below:
<root xmlns:v4="financetypes:defn:v4" xmlns:v5="financetypes:defn:v5">
<v4:PS>version 4</v4:PS>
<v5:PS>version 5</v5:PS>
</root>
You will be able to unmarshall properly.
Update to respond to the comment:
You use xsd to generate the classes. You did not provide the xsd so I will assume you are not allowed to. I created an xsd to generate the classes you show in your question. The namespace.xsd looks like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:v4="financetypes:defn:v4" xmlns:v5="financetypes:defn:v5">
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="v4PSType" type="PSTypev4" />
<xs:element name="v5PSType" type="PSTypev5" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:complexType name="PSTypev4">
<xs:simpleContent>
<xs:extension base="xs:string" />
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="PSTypev5">
<xs:simpleContent>
<xs:extension base="xs:string" />
</xs:simpleContent>
</xs:complexType>
</xs:schema>
Then your bindings would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
jaxb:extensionBindingPrefixes="xjc">
<jaxb:bindings schemaLocation="../xsd/namespaces.xsd">
<jaxb:bindings node="//xs:complexType[#name='PSTypev4']">
<annox:annotate target = "class">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlType" name="v4PSType" namespace="financetypes:defn:v4" />
</annox:annotate>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[#name='PSTypev5']">
<annox:annotate target = "class">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlType" name="v5PSType" namespace="financetypes:defn:v5" />
</annox:annotate>
</jaxb:bindings>
<jaxb:bindings node="//xs:element[#name='root']//xs:complexType//xs:all//xs:element[#name='v5PSType']">
<annox:annotate target = "field">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlElement" name="PS" namespace="financetypes:defn:v5" />
</annox:annotate>
</jaxb:bindings>
<jaxb:bindings node="//xs:element[#name='root']//xs:complexType//xs:all//xs:element[#name='v4PSType']">
<annox:annotate target = "field">
<annox:annotate annox:class="javax.xml.bind.annotation.XmlElement" name="PS" namespace="financetypes:defn:v4" />
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
And then you would end up with classes as those in my answer.
Related
I have a JAXB class, which has an element coming from another namespace. I would like to have an ANY element as well, which collects all the elements not described in the JAXB class. So I added a List<Object> annotated with the #XmlAnyElement.
I have generated an XSD from the JAXB class, but when I am validating I am getting an error: "cos-nonambig: "nb":b and WC[##other:""] (or elements from their substitution group) violate "Unique Particle Attribution". During validation against this schema, ambiguity would be created for those two particles."
The JAXB class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType
public class Foo {
#XmlElement
String a;
#XmlElement(namespace="nb")
Bar b;
#XmlAnyElement
List<Object> other;
}
The XSD generated by JAXB
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:ns1="nb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="nb" schemaLocation="schema1.xsd"/>
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
<xs:element ref="ns1:b" minOccurs="0"/>
<xs:any processContents="skip" namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bar">
<xs:sequence>
<xs:element name="bid" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="nb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="schema2.xsd"/>
<xs:element name="b" type="bar"/>
</xs:schema>
How should I add the XmlAnyElement to pass the validation?
I have an xml:
<package>
<metadata>
<title>Title</title>
<language>en</language>
<meta name="cover" />
</metadata>
</package>
Another examples of correct xml's:
<package>
<metadata>
<language>en</language>
<title>Title</title>
</metadata>
</package>
<package>
<metadata>
<meta name="content" />
<language>en</language>
<meta name="cover" />
<title>Title</title>
</metadata>
</package>
And I want to unmarshall it to the java class using JAXB library.
The difficulty is that amount of "meta" element can be from 0 to multiple and order of elements "title" "language" and "meta"s can also be random.
My class looks like:
#XmlRootElement(name = "package")
#XmlAccessorType(XmlAccessType.FIELD)
public class Test {
#XmlElement(name = "metadata", required = true)
public Metadata metadata;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder={})
public static class Metadata {
#XmlElement(name = "title", required = true)
public String title;
#XmlElement(name = "language", required = true)
public String language;
#XmlElement(name = "meta", required = false)
public List<Meta> metas;
}
#XmlAccessorType(XmlAccessType.FIELD)
public static class Meta {
#XmlAttribute(name = "name", required = true)
public String name;
}
}
It matches the schema:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="package" type="test"/>
<xs:complexType name="test">
<xs:sequence>
<xs:element name="metadata" type="metadata"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="metadata">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="language" type="xs:string"/>
<xs:element name="meta" type="meta" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="meta">
<xs:sequence/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
When I unmarshall the document I get an error:
org.xml.sax.SAXParseException: cos-all-limited.2: The {max occurs} of an element in an 'all' model group must be 0 or 1. The value 'unbounded' for element 'meta' is invalid.
If I remove the attribute #XmlType(propOrder={}) it matches the schema:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="package" type="test"/>
<xs:complexType name="test">
<xs:sequence>
<xs:element name="metadata" type="metadata"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="metadata">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="language" type="xs:string"/>
<xs:element name="meta" type="meta" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="meta">
<xs:sequence/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
And I get an error if the order of the properties is different:
Invalid content was found starting with element 'language'. One of '{title}' is expected.
I can not change the xml files, but I can modify the classes and/or annotations. I generate schema by this classes dynamically, so the schema is also can be adjust.
Any ideas how to achieve a desirable behaviour?
In JAXB when using automatic class generation via xjc from xsd scheme.
alpha.xsd
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="alpha">
<xs:complexType>
<xs:sequence>
<xs:element name="persons">
<xs:complexType>
<xs:sequence>
<xs:element name="person" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
beta.xml
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="country">
<xs:complexType>
<xs:sequence>
<xs:element name="class">
<xs:complexType>
<xs:sequence>
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
As you can see there is Person element which is shared among these two schemes. What I would like to do is:
generate classes using xjc in a way that ObjectFactory class is shared for both schema classes (the output classes will be in one package)
not use nested static classes (with attribute localScoping="toplevel")
use Person class to bind with /alpha/persons/person as with /country/class/person so there are not two Person classes created
The purpose of this is unmarshalling one xml, applying business logic and creating another one as output where some elements (like Person) are same and shared for both xml files. The namespace will be the same for both files.
I would welcome if you can present me with complete .xjb bindings settings file. So far mine contains only:
<jxb:bindings version="1.0"
xmlns:jxb="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"
jxb:extensionBindingPrefixes="xjc">
<jxb:globalBindings localScoping="toplevel"/>
</jxb:bindings>
And of course I get name collision error as I do not know how to set binding compiler to see Person as the same entity/element.
You can use an external binding file to indicate that during class generation we wish to use our existing class for the complex type called Document.
binding.xml
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="beta.xsd">
<jxb:bindings node="//xs:element[#name='person']/complexType">
<jxb:class ref="alpha.Person"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
XJC Call
xjc -b binding.xml beta.xsd
If namespace of person from A will be equals namespace person from B, that xjc has to generate the correct classes.
Lets say I have the following XML schema:
<xs:schema
xmlns="http://www.example.com/data"
xmlns:data="http://www.example.com/data"
targetNamespace="http://www.example.com/data"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="data">
<xs:complexType>
<xs:all>
<xs:element name="countries">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="country" type="country"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="types">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="type" type="type"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="products">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="product" type="product"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:key name="countryNameKey">
<xs:selector xpath=".//data:country"/>
<xs:field xpath="#name"/>
</xs:key>
<xs:key name="typeNameKey">
<xs:selector xpath=".//data:type"/>
<xs:field xpath="#name"/>
</xs:key>
<xs:keyref name="countryNameRef" refer="data:countryNameKey">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#country"/>
</xs:keyref>
<xs:keyref name="typeNameRef" refer="data:typeNameKey">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#type"/>
</xs:keyref>
<xs:unique name="uniqueProducts">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#country"/>
<xs:field xpath="#type"/>
</xs:unique>
</xs:element>
<xs:complexType name="country">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="type">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="product">
<xs:attribute name="country" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
Excuse the contrived example.
As you can see it is tabular data. I define some countries, then I define some types of product. I then define individual products as a type from a country, cheese from France for example.
The important thing to note here is that I use key and keyref to cross-reference all products back to the original country/type.
So, my question is:
Is it possible to compile this schema into java classes that can be unmarshalled using Eclipse Moxy with the cross-references intact?
I know that the JAXB 2.0 spec does not support key/keyref. I also know that Moxy Does.1
Further I know that Moxy doesn't have a Maven plugin and, in any case, uses XJC generated classes and simply adds in a jaxb.properties file to specify the JAXB provider to use.2
So I suspect the answer to my question is "no, you have to craft the classes yourself", but I thought I'd check before I abandoned hope.
To clarify, My product element currently compiles (using maven-jaxb2-plugin) to
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "product")
public class Product implements Cloneable, CopyTo, Equals, HashCode, ToString {
#XmlAttribute(name = "country", required = true)
protected String country;
#XmlAttribute(name = "type", required = true)
protected String type;
//getters and setters
}
It, references the Strings rather than the Country and Type objects.
Currently EclipseLink JAXB (MOXy) only extends the XJC tool to add a jaxb.properties file that indicates that MOXy is the JAXB (JSR-222) provider. I have entered the following enhancement (currently unscheduled) to track this request:
http://bugs.eclipse.org/411619
I have a xsd that contains something like:
<xs:complexType>
<xs:sequence minOccurs="0">
<xs:element ref="HereIsTheProblem"/>
<xs:element ref="blaBla"/>
</xs:sequence>
<xs:attribute name="something" type="xs:string" use="required">
<xs:annotation/>
</xs:attribute>
<xs:attribute name="somethingElse" type="xs:string">
<xs:annotation/>
</xs:attribute>
<xs:attribute name="HereIsTheProblem" type="xs:string">
<xs:annotation/>
</xs:attribute>
</xs:complexType>
now when i try to parse the schema using jaxb to generate java classes it fails:
[ERROR] Element "{http://something.somemorething.com/etc/}HereIsTheProblem" shows up in more than one properties.
how to resolve this without making any modification in the schema?
PS:my jaxb version is 2.1.13
You need to use a binding file indicating jaxB how it should handle this name collision. For example, put something like this in a file named something like bindings.xjb:
<jaxb:bindings version="2.1" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:com.fnf="http://www.fnf.com/xes">
<jaxb:bindings schemaLocation="your schema location here" node="/xs:schema">
<jaxb:bindings node="//XPath selector">
<jaxb:property name="HereIsTheProblem2" />
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Can't provide you a complete solution without a complete schema
Also we can modify the XSD as below.
<xs:complexType>
<xs:sequence minOccurs="0">
<xs:element ref="HereIsTheProblem"/>
<xs:element ref="blaBla"/>
</xs:sequence>
<xs:attribute name="something" type="xs:string" use="required">
<xs:annotation/>
</xs:attribute>
<xs:attribute name="somethingElse" type="xs:string">
<xs:annotation/>
</xs:attribute>
<xs:attribute name="HereIsTheProblem" type="xs:string">
<xs:annotation>
<xs:appinfo>
<jaxb:property name="HereIsTheProblemAttr"/>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
</xs:complexType>
The main issue is inside the pojo class, if we have the element and the attribute with the same name, it will try to create variables with the same name which is not allowed in simple java principles. So we can define the variable name to be different from one another like above.