Problems with Jaxb generation - maven

I have a problem with my JAXB-Generation. I have two XSDs (both in the same hierarchiy) which have a quite similiar schema-definition:
A.xsd
<xs:schema>
<xs:element name="A">
<xs:complexType>
<xs:sequence>
<xs:element name="CacheInfo">
<xs:complexType>
<xs:complexContent>
<xs:extension base="CacheType">
<xs:sequence ... />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element> <!--CacheInfo -->
</xs:sequence>
</xs:complexType>
</xs:element> <!-- A -->
<xs:complexType name="CacheType" ... />
<xs:complexType name="TimeType" ... />
</xs:schema>
B.xsd
<xs:schema>
<xs:element name="B">
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:element name="CacheInfo" type="CacheType">
</xs:element> <!--CacheInfo -->
<xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element> <!-- B -->
<xs:complexType name="CacheType" ... />
<xs:complexType name="TimeType" ... />
</xs:schema>
The structure of CacheType in this two XSDs is different. Its only the name the same.
My problem now is, that, when I try to generate the code I got this error:
[ERROR] file:A.xsd [95,38]
org.xml.sax.SAXParseException; systemId: file:A.xsd; lineNumber: 95; columnNumber: 38; 'CacheType' is already defined (same issue for TimeType)
When I remove one of the files, the generation is ok. I am not able to edit the XSDs, so I need a binding-file to rename the types for the two special cases:
<bindings schemaLocation="../xsd/A.xsd" node="//xs:complexType[#name='CacheType']">
<class name="ACacheType" />
</bindings>
<bindings schemaLocation="../xsd/B.xsd" node="//xs:complexType[#name='CacheType']">
<class name="BCacheType" />
</bindings>
But this doesnt work.
It also doesnt work, when I try to bind the types to a property (I am ending up in the same error):
<bindings schemaLocation="../xsd/A.xsd">
<bindings node="//xs:complexType[#name='CacheType']">
<property name="ACacheType" />
</bindings>
<bindings node=".//xs:complexType[#name='TimeType']">
<property name="ATimeType" />
</bindings>
</bindings>
<bindings schemaLocation="../xsd/B.xsd">
<bindings node="//xs:complexType[#name='CacheType']">
<property name="BCacheType" />
</bindings>
<bindings node=".//xs:complexType[#name='TimeType']">
<class name="BTimeType" />
</bindings>
</bindings>
Is there anything I dont see? Why I cant generate these two XSDs with these bindings?
To complete this, here is my pom.xml snippet:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>generate-htng-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
</plugin>

you need to define them at their own package
This will generate the same classes but in different packages, so it wont be a problem.
<jaxb:bindings schemaLocation="../xsd/A.xsd">
<jaxb:schemaBindings>
<jaxb:package name="packagea" />
</jaxb:schemaBindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="../xsd/B.xsd">
<jaxb:schemaBindings>
<jaxb:package name="packageb" />
</jaxb:schemaBindings>
</jaxb:bindings>
i havent used this plugin. i use the following:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<bindingDirectory>src/main/resources/xsd</bindingDirectory>
<bindingIncludes>
<include>*.xjb</include>
</bindingIncludes>
<generateDirectory>${project.build.directory}/generated-sources</generateDirectory>
</configuration>
</execution>
</executions>
</plugin>
you can try with this too to see if you get any errors.

First, I'd ensure that the binding files are in the location expected by the jaxb2-maven-plugin. Specifying a package with a schemaBinding as mentioned by #Apostolos should have worked even without changing the plugin as I read the docs.
If the binding files are being applied, then one thing I notice is the bindings mentioned in the original question use a mix of property and class:
<bindings schemaLocation="../xsd/A.xsd">
<bindings node="//xs:complexType[#name='CacheType']">
<property name="ACacheType" /> <!-- property -->
</bindings>
<bindings node=".//xs:complexType[#name='TimeType']">
<property name="ATimeType" /> <!-- property -->
</bindings>
</bindings>
<bindings schemaLocation="../xsd/B.xsd">
<bindings node="//xs:complexType[#name='CacheType']">
<property name="BCacheType" /> <!-- property -->
</bindings>
<bindings node=".//xs:complexType[#name='TimeType']">
<class name="BTimeType" /> <!-- class -->
</bindings>
</bindings>
This document from Oracle has a section near the bottom on resolving conflicts. One example shows an element with name 'Class' which is a Java reserved word. They fix the conflict by specifying both property and class:
<jxb:bindings node="//xs:element[#name='Class']">
<jxb:class name="Clazz"/>
<jxb:property name="Clazz"/>
</jxb:bindings>
So I wonder, does it work if the binding is modified to specify both?
<bindings schemaLocation="../xsd/A.xsd">
<bindings node="//xs:complexType[#name='CacheType']">
<class name="ACacheType" />
<property name="ACacheType" />
</bindings>
... repeat for TimeType ....
</bindings>

Related

XML Schema 1.0 - qualified versus unqualified: what specifically changes in a valid instance?

Say I have a valid XML instance file ("1") that contains only elements in the targetNamespace of its schema (Schema "A"). The instance is valid per this schema. Instance 1 has the correct namespace declaration for its schema on its (1's) root node, and nowhere else.
Now I take the same instance 1 and try to validate it against Schema "B".
B is identical to A except I changed elementFormDefault="unqualified" to elementFormDefault="qualified".
I am seeing 1 failing to validate against B. Why? What do I need to change in 1 (producing instance "2") to make it valid again against B?
Is the "qualified" flavor of an XML schema just for instances with an explicit namespace prefix on every single element?
Example schemas: All based on a minimal XML structure for communicating some data structures like file/record/info1. Unfortunately these seem to behave differently again from my real-world examples (which are too big to post here).
A: UNqualified schema
<?xml version="1.0" encoding="UTF-8"?>
<!-- The UNqualified version -->
<xs:schema elementFormDefault="unqualified" targetNamespace="http://example.com/xsd-prefixes-test"
xmlns:test="http://example.com/xsd-prefixes-test" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="file">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="test:record" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="record">
<xs:complexType>
<xs:sequence>
<xs:element ref="test:info1" />
<xs:element ref="test:info2" />
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="status" type="xs:NCName" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="info1">
<xs:complexType />
</xs:element>
<xs:element name="info2">
<xs:complexType />
</xs:element>
</xs:schema>
B: QUALIFIED schema
<?xml version="1.0" encoding="UTF-8"?>
<!-- The QUALIFIED version -->
<xs:schema elementFormDefault="qualified" targetNamespace="http://example.com/xsd-prefixes-test"
xmlns:test="http://example.com/xsd-prefixes-test" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="file">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="test:record" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="record">
<xs:complexType>
<xs:sequence>
<xs:element ref="test:info1" />
<xs:element ref="test:info2" />
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="status" type="xs:NCName" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="info1">
<xs:complexType />
</xs:element>
<xs:element name="info2">
<xs:complexType />
</xs:element>
</xs:schema>
Example schema instances:
Instance 1 - prefixes for the targetNamespace on all elements; validates against both schemas
<?xml version="1.0" encoding="UTF-8"?>
<!-- ALL prefixes -->
<test:file xmlns:test="http://example.com/xsd-prefixes-test"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/xsd-prefixes-test xsd-prefixes-test_qualified.xsd">
<!-- validates against xsd-prefixes-test_UNqualified.xsd AND xsd-prefixes-test_qualified.xsd -->
<test:record id="1" status="ok">
<test:info1 />
<test:info2 />
<!-- etc... -->
</test:record>
<test:record id="1" status="ok">
<test:info1 />
<test:info2 />
<!-- etc... -->
</test:record>
<test:record id="1" status="duplicate_deprecated">
<test:info1 />
<test:info2 />
<!-- etc... -->
</test:record>
</test:file>
Instance 2: - no namespace prefixes anywhere but still validates against A and B!
<?xml version="1.0" encoding="UTF-8"?>
<!-- NO prefixes anywhere -->
<file xmlns="http://example.com/xsd-prefixes-test" xmlns:test="http://example.com/xsd-prefixes-test"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/xsd-prefixes-test xsd-prefixes-test_qualified.xsd">
<!-- validates against BOTH xsd-prefixes-test_UNqualified.xsd AND xsd-prefixes-test_qualified.xsd -->
<record id="1" status="ok">
<info1 />
<info2 />
<!-- etc... -->
</record>
<record id="1" status="ok">
<info1 />
<info2 />
<!-- etc... -->
</record>
<record id="1" status="duplicate_deprecated">
<info1 />
<info2 />
<!-- etc... -->
</record>
</file>
Instance 3 - does not validate against either A or B - why not?
<?xml version="1.0" encoding="UTF-8"?>
<!-- NO prefixes anywhere -->
<test:file xmlns:test="http://example.com/xsd-prefixes-test"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/xsd-prefixes-test xsd-prefixes-test_qualified.xsd">
<!-- validates against NEITHER xsd-prefixes-test_UNqualified.xsd NOR xsd-prefixes-test_qualified.xsd -->
<record id="1" status="ok">
<info1 />
<info2 />
<!-- etc... -->
</record>
<record id="1" status="ok">
<info1 />
<info2 />
<!-- etc... -->
</record>
<record id="1" status="duplicate_deprecated">
<info1 />
<info2 />
<!-- etc... -->
</record>
</test:file>
Error messages (same with both schemas A and B):
Instance 3 - cvc-complex-type.2.4.a: Invalid content was found starting with element 'record'. One of '{"http://example.com/xsd-prefixes-test":record}' is expected.
I am seeing this error or very similar with instance files along the pattern of both 1 and 2, when used with the schema of the "opposite" flavor (an instance with prefixes against a schema with unqualified).
Conversely I am seeing instances of style 3 that do validate against the qualified type schema.
Is there a dependency on what language/parser/validation engine is used?

Apache CXF and Apache Camel: the given SOAPAction does not match an operation

I'm trying to walk through the Camel Report Incident tutorial and am stuck at the end of part 5. When I try to run the unit test it fails with the message The given SOAPAction http://reportincident.example.camel.apache.org/ReportIncident does not match an operation.
I saw a similar question where the problem was that the declared soapAction attribute on the WSDL file had a different value from the actual SOAP request. This does not seem to be my case. Any ideas about what is going wrong? Thanks in advance.
reportIncident.wsdl
<?xml version="1.0" encoding="ISO-8859-1"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://reportincident.example.camel.apache.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://reportincident.example.camel.apache.org">
<!-- Type definitions for input- and output parameters for webservice -->
<wsdl:types>
<xs:schema targetNamespace="http://reportincident.example.camel.apache.org">
<xs:element name="inputReportIncident">
<xs:complexType name="inputReportIncident">
<xs:sequence>
<xs:element type="xs:string" name="incidentId" />
<xs:element type="xs:string" name="incidentDate" />
<xs:element type="xs:string" name="givenName" />
<xs:element type="xs:string" name="familyName" />
<xs:element type="xs:string" name="summary" />
<xs:element type="xs:string" name="details" />
<xs:element type="xs:string" name="email" />
<xs:element type="xs:string" name="phone" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="outputReportIncident">
<xs:complexType name="outputReportIncident">
<xs:sequence>
<xs:element type="xs:string" name="code" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<!-- Message definitions for input and output -->
<wsdl:message name="inputReportIncident">
<wsdl:part name="parameters" element="tns:inputReportIncident" />
</wsdl:message>
<wsdl:message name="outputReportIncident">
<wsdl:part name="parameters" element="tns:outputReportIncident" />
</wsdl:message>
<!-- Port (interface) definitions -->
<wsdl:portType name="ReportIncidentEndpoint">
<wsdl:operation name="ReportIncident">
<wsdl:input message="tns:inputReportIncident" />
<wsdl:output message="tns:outputReportIncident" />
</wsdl:operation>
</wsdl:portType>
<!-- Port bindings to transports and encoding - HTTP, document literal
encoding is used -->
<wsdl:binding name="ReportIncidentBinding" type="tns:ReportIncidentEndpoint">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="ReportIncident">
<soap:operation soapAction="http://reportincident.example.camel.apache.org/ReportIncident" style="document" />
<wsdl:input>
<soap:body parts="parameters" use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body parts="parameters" use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!-- Service definition -->
<wsdl:service name="ReportIncidentService">
<wsdl:port name="ReportIncidentPort" binding="tns:ReportIncidentBinding">
<soap:address location="http://reportincident.example.camel.apache.org" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
route definition (inside a RouteBuilder subclass)
OutputReportIncident ok = new OutputReportIncident();
ok.setCode("0");
// endpoint to our CXF webservice
String cxfEndpoint = "cxf://http://localhost:8080/part-five/webservices/incident"
+ "?serviceClass=org.apache.camel.example.reportincident.ReportIncidentEndpoint"
+ "&wsdlURL=reportIncident.wsdl";
// first part from the webservice -> file backup
from(cxfEndpoint)
// we need to convert the CXF payload to InputReportIncident that FilenameGenerator and velocity expects
.convertBodyTo(InputReportIncident.class)
// then set the file name using the FilenameGenerator bean
.setHeader("CamelFileName", BeanLanguage.bean(FilenameGenerator.class, "generateFilename"))
// transform the message using velocity to generate the mail message
.to("velocity:mailBody.vm")
// and store the file
.to("file://target/subfolder")
// return OK as response
// usando transformação!
.transform(constant(ok));
pom.xml (wsdl2java is used to generate Java files from WSDL)
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.13.0</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/reportIncident.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
test code
package org.apache.camel.example.reportincident;
import static org.junit.Assert.*;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.junit.Test;
import org.jvnet.mock_javamail.Mailbox;
public class ReportIncidentRoutesTest {
// should be the same address as we have in our route
private static String ADDRESS = "http://localhost:8080/part-five/webservices/incident";
private CamelContext context;
#Test
public void testRendportIncident() throws Exception {
// start camel
startCamel();
// assert mailbox is empty before starting
Mailbox inbox = Mailbox.get("incident#mycompany.com");
assertEquals("Should not have mails", 0, inbox.size());
// create input parameter
InputReportIncident input = new InputReportIncident();
input.setIncidentId("123");
input.setIncidentDate("2008-08-18");
input.setGivenName("Claus");
input.setFamilyName("Ibsen");
input.setSummary("Bla");
input.setDetails("Bla bla");
input.setEmail("davsclaus#apache.org");
input.setPhone("0045 2962 7576");
// create the webservice client and send the request
ReportIncidentEndpoint client = createCXFClient();
OutputReportIncident out = client.reportIncident(input);
// assert we got a OK back
assertEquals("0", out.getCode());
// let some time pass to allow Camel to pickup the file and send it as an email
Thread.sleep(3000);
// assert mail box
assertEquals("Should have got 1 mail", 1, inbox.size());
// stop camel
context.stop();
}
private void startCamel() throws Exception {
context = new DefaultCamelContext();
context.disableJMX();
context.addRoutes(new ReportIncidentRoutes());
context.start();
}
private ReportIncidentEndpoint createCXFClient() {
// we use CXF to create a client for us as its easier than JAXWS and works
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ReportIncidentEndpoint.class);
factory.setAddress(ADDRESS);
return (ReportIncidentEndpoint) factory.create();
}
}
I think you just need to pass the WSDL url to the JaxWsProxyFactoryBean and it can take care of the soap action for you.
Please change the ReportIncidentRoutesTest.createCXFClient() like this
private ReportIncidentEndpoint createCXFClient() {
// we use CXF to create a client for us as its easier than JAXWS and works
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ReportIncidentEndpoint.class);
factory.setWsdlURL("reportIncident.wsdl");
factory.setAddress(ADDRESS);
return (ReportIncidentEndpoint) factory.create();
}

Is it necessary to maintain certain order inside oozie action content?

When i tried to run oozie hive action with the following code
<action name="Hive-Node">
<hive xmlns="uri:oozie:hive-action:0.2">
<job-tracker>${jobTracker}</job-tracker>
<name-node>${nameNode}</name-node>
<job-xml>hive-site.xml</job-xml>
<prepare>
<mkdir path="${nameNode}/hive/output"/>
</prepare>
<configuration>
<property>
<name>mapred.job.queue.name</name>
<value>${queueName}</value>
</property>
<property>
<name>hive.insert.into.multilevel.dirs</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>${hbaseZooQuorum}</value>
</property>
</configuration>
<script>${HIVE_QUERY_FILE}</script>
</hive>
<ok to="End" />
<error to="Fail" />
</action>
I got the following error:
Error: E0701 : E0701: XML schema error, cvc-complex-type.2.4.a: Invalid content was found starting with element 'prepare'. One of '{"uri:oozie:hive-action:0.2":configuration, "uri:oozie:hive-action:0.2":script}' is expected.
But after I modified the order of declaring tags inside hive action i.e moved <job-xml>...</job-xml> after <prepare>...</prepare>, it works fine.
Is it necessary to follow those order(s) inside oozie actions ?
From the Oozie Hive Action Documentation,
The schema uses,
<xs:sequence>
<xs:element name="job-tracker" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="name-node" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="prepare" type="hive:PREPARE" minOccurs="0" maxOccurs="1"/>
<xs:element name="job-xml" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="configuration" type="hive:CONFIGURATION" minOccurs="0" maxOccurs="1"/>
<xs:element name="script" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="param" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="file" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="archive" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
the element xs:sequence which as per W3Schools,
The sequence element specifies that the child elements must appear in
a sequence. Each child element can occur from 0 to any number of
times.
And we can see as per the schema for Hive-Action <prepare> comes before <job-xml> in sequence

XSD key not in root element and complex keys

I searched for this, but can't find solution to my problem, so please don't trash this question.
We have a service with very complex XML configuration which is described by XSD. There are many rules that must be obeyed for things to run smoothly. XSD describes structure of configuration, but not the rules, which we must do now. After creating some global rules we have to do some more complex now and we encountered a problem. It seams like validator only uses key/keyref/unique from root element. I've created small XSD and XML file to illustrate that:
XSD:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://test.org/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns="http://test.org/XMLSchema.xsd"
xmlns:t="http://test.org/XMLSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Orders" type="t:OrdersList">
<xs:key name="OrderNo">
<xs:selector xpath="./t:Order" />
<xs:field xpath="#Number" />
</xs:key>
</xs:element>
<xs:complexType name="OrdersList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Order" nillable="false" type="t:Order" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Order">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList" />
</xs:sequence>
<xs:attribute name="Number" use="optional" type="xs:string" />
<xs:attribute name="ClientId" use="optional" type="xs:int" />
</xs:complexType>
<xs:complexType name="OrdersLinesList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Line" nillable="false" type="t:OrderLine">
<!-- THE PROBLEM -->
<xs:key name="LineNoKey">
<xs:selector xpath="./t:Line" />
<xs:field xpath="#LineNumber" />
</xs:key>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="OrderLine">
<xs:attribute name="LineNumber" use="optional" type="xs:string" />
<xs:attribute name="ProductId" use="optional" type="xs:int" />
<xs:attribute name="Amount" use="optional" type="xs:decimal" />
</xs:complexType>
</xs:schema>
XML:
<?xml version="1.0" encoding="utf-8"?>
<Orders xmlns="http://test.org/XMLSchema.xsd">
<Order Number="0001/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<Line LineNumber="2" ProductId="124" Amount="4" />
</Lines>
</Order>
<Order Number="0002/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<!-- Duplicate number - it DOES validate as expected. -->
<Line LineNumber="1" ProductId="124" Amount="4" />
</Lines>
</Order>
<!-- Duplicate number - it doesn't validate as expected. -->
<Order Number="0002/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<Line LineNumber="2" ProductId="124" Amount="4" />
</Lines>
</Order>
</Orders>
I have a few questions which I can't find any sensible answer:
How to solve the above. LineNumber must be unique, but only within Order/Lines.
Is it possible to allow keyref to contain non existing virtual value (our service uses some predefined... let say things. Custom ones are defined in XML to allow extending functionality, but in most of the cases, users will use predefined ones)
Is there any way to determine if list of elements within a tag (something like Lines above) has at least one tag with attribute set to certain value. Good example would be to describe it like a list of tables with unique names, that has list of columns with unique names and at least one of the columns is a primary key.
This is the corrected constraint for Lines/Line:
<xs:complexType name="Order">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList">
<!-- THE PROBLEM SOLVED -->
<xs:key name="LineNoKey">
<xs:selector xpath="t:Line"/>
<xs:field xpath="#LineNumber"/>
</xs:key>
</xs:element>
</xs:sequence>
<xs:attribute name="Number" use="optional" type="xs:string"/>
<xs:attribute name="ClientId" use="optional" type="xs:int"/>
</xs:complexType>
If always helps if you can visualize your constraints, to understand the scope they act upon:
The correct diagram:
vs. the original one:
You can see that the selector rooted in the element Line is looking for yet another Line (./t:Line); and even if you fix the selector, it'll always match at most one attribute. The idea of a key is that the selector should match a set of nodes among which the field must be present and unique.
The above should take care of 1.
No.
Not based on an attribute. To stick with your parallel, for XSD 1.0 I would probably enforce an element called PrimaryKey, which should contain one or more references to names of the other columns; as if instead of using the PRIMARY KEY constraint clause in a column definition, I would enforce the use of the same at the table level.

Missing #XmlRootElement when creating a client from a wsdl

I have a question in regards to consuming a web service based on a third party wsdl file.
I've taken the given wsdl and generated the 120+ java files required. This process was done by using xjc. Within the Sping environment, I was able to successfully create a couple of JUnit tests by calling a couple of the exposed services.
But, in order to successfully test those services I had to add the #XmlRootElement annotation to the generated java files. Otherwise, I would encounter an error stating
"com.sun.istack.SAXException2: unable to marshal type
"com.beam.services.client.UserGetRequestData" as an element because it
is missing an #XmlRootElement annotation"
.
I've exhausted my search… I have no control as to how the wsdl file is created/structured. How can I go about generating the java files to ensure that the #XmlRootElement annotation is included or go about writing the client side code in way to avoid the error above?
Thank you.
If you really need the #XmlRootElement you could use simple binding mode if your type is used for only one element. The reason why JAXB does not include the annotation by default and how to use simple binding is explained here: https://community.oracle.com/blogs/kohsuke/2006/03/03/why-does-jaxb-put-xmlrootelement-sometimes-not-always:
your schema might be used by other schemas that XJC isn't compiling
right now
and
Such notion isn't defined in the spec, but as an experiment we have
such aggressive optimization mode in XJC, tentatively called
"simple-minded binding mode".
The sample seems to got lost when the moved the blog, but it looked like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionbindingprefixes="xjc">
<xs:annotation>
<xs:appinfo>
<jaxb:globalbindings>
<xjc:simple/>
</jaxb:globalbindings>
</xs:appinfo>
</xs:annotation>
<xs:element name="foo" type="bar"/>
<xs:complextype name="bar"/>
</xs:schema>
The other possibilty is to wrap it in a JAXBElement. The ObjectFactory should include a method for creating these wrapped objects.
If you are using mavem then check this link it worked for me.
Create Maven project. Below you can see the POM:
<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>org.zmeu</groupId>
<artifactId>zmeu-blog-maven-jaxb</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ZMEU Blog Maven JAXB</name>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<configuration>
<schemaDirectory>src/main/resources/schema</schemaDirectory>
<bindingDirectory>src/main/resources/schema</bindingDirectory>
<generatePackage>org.zmeu.blog.jaxb</generatePackage>
<strict>false</strict>
<extension>true</extension>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.2</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>0.6.2</version>
</plugin>
</plugins>
<args>
<arg>-Xannotate</arg>
<arg>-XtoString</arg>
</args>
</configuration>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-runtime</artifactId>
<version>0.6.2</version>
</dependency>
</dependencies>
</project>
Write XML Schema (schema.xsd):
<?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="user" type="user" />
<xs:element name="userList" type="userList" />
<xs:complexType name="user">
<xs:all>
<xs:element name="id" type="xs:long" minOccurs="0" />
<xs:element name="name" type="xs:string" />
<xs:element name="registrationDate" type="xs:dateTime" />
</xs:all>
</xs:complexType>
<xs:complexType name="userList">
<xs:sequence>
<xs:element name="user" type="user" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Customize JAXB Bindings (binding.xjb):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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"
xmlns:annox="http://annox.dev.java.net"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<jaxb:globalBindings>
<!-- Use java.util.Calendar instead of javax.xml.datatype.XMLGregorianCalendar for xs:dateTime -->
<jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
<!-- Force all classes implements Serializable -->
<xjc:serializable uid="1" />
</jaxb:globalBindings>
<!-- Annotate the following classes with XmlRootElement -->
<jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
<jaxb:bindings node="xs:complexType[#name='user']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="user" />
</annox:annotate>
</jaxb:bindings>
<jaxb:bindings node="xs:complexType[#name='userList']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="userList" />
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Run the build using mvn clean install command. Build must be successful. Generated classes will be located in target/generated-sources/xjc directory. Below is a snippet from generated User class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "user", propOrder = {})
#XmlRootElement(name = "user")
public class User implements Serializable, ToString {
private final static long serialVersionUID = 1L;
protected Long id;
#XmlElement(required = true)
protected String name;
#XmlElement(required = true, type = String.class)
#XmlJavaTypeAdapter(Adapter1 .class)
#XmlSchemaType(name = "dateTime")
protected Calendar registrationDate;
}
You are done!

Resources