wsimport: adding Binding when the XSD is embedded in WSDL? - java

I'm trying to generate some java code from the following WSDL: http://www.ebi.ac.uk/Tools/services/soap/emboss_needle?wsdl
$ wsimport -keep "http://www.ebi.ac.uk/Tools/services/soap/emboss_needle?wsdl"
however it generates some JAXBElement<String> instead of String. So I've tried to use a xjb binding as it is described here: Get rid of JAXBElement in classes generated by wsimport called from ant
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<jxb:bindings>
<jxb:globalbindings generateelementproperty="false">
<jxb:javatype name="java.lang.String" xmltype="xs:string"/>
</jxb:globalbindings>
</jxb:bindings>
</jxb:bindings>
but wsimport raises an exception:
$ wsimport -keep -b binding.xjb "http://www.ebi.ac.uk/Tools/services/soap/emboss_needle?wsdl"
[ERROR] The "jxb:globalbindings" customization is not associated with any schema element.
line 6 of file:/home/lindenb/tmp/WS/biostar14996.xjb
The XSD schema is embedded in the WSDL document. What URI should I give for the jxb:schemaLocation ? How can I fix that problem ?
Thanks,
P.

Eventually I ended up with:
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" wsdlLocation="YOUR_WSDL_LOCATION">
<jxb:globalBindings generateElementProperty="false"/>
</jxb:bindings>

The EMBL-EBI's EMBOSS needle service (http://www.ebi.ac.uk/Tools/services/soap/emboss_needle?wsdl), and most of their other analysis tool services (see http://www.ebi.ac.uk/Tools/webservices/) allow for submission parameters to have three states:
Explicit value
Null value
To be omitted
This provides compatibility with a wide range of SOAP tool-kits, some of which assume only one or two out of these three behaviors.
An unfortunate side-effect of this is that tool-kits such as JAX-WS, which understand that there are three states, need to use a more complex representation to handle this. Thus the JAXBElement classes are required. EMBL-EBI provides sample clients with source code using JAX-WS for their InterProScan (SOAP) and NCBI BLAST (SOAP) services, which use the same pattern for their parameters (see http://www.ebi.ac.uk/Tools/webservices/tutorials/06_programming/java/soap/jax-ws).

I believe your problem is similar to this post; there are links pointing you to the documentation, as well as the solution; basically, when you bind against WSDL files, you need a different top level element; the accepted response gives you the command line as well.

Related

Multiple XSD implementing the same targetNamespace - is this correct?

I implemented an xsd scanner, which creates an targetNamespace=<file.xsd> catalog.
Includes are filtered, so the catalog has only the root files of the targetNamespace.
With this catalog I'm resolving the required files (using a LSResourceResolver) to validate incoming xml files.
Map
namespace1=path/xsdForNameSpace1
namespace2=path/xsdForNameSpace2
:
But now I got multiple XSD, containing different content, but implementing the same targetNamespace.
Imho this is not correct, one namespace one root xsd - done
Example
schema1.xsd:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.xxxxxxx.com/texxxxxxx"
targetNamespace="http://www.xxxxxxx.com/texxxxxxx"
elementFormDefault="qualified">
<xsd:include schemaLocation="xxxxxx_xxxxxx_xxxxx_xxxxx.xsd"/>
<xsd:element name="ab120">
<xsd:complexType>
:
schema2.xsd:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.xxxxxxx.com/texxxxxxx"
targetNamespace="http://www.xxxxxxx.com/texxxxxxx"
elementFormDefault="qualified">
<xsd:include schemaLocation="xxxxxx_xxxxxx_xxxxx_xxxxx.xsd"/>
<xsd:element name="ab122">
<xsd:complexType>
:
I have two xml files are implementing the identical namespace http://www.xxxxxxx.com/texxxxxxx one with a root element ab120 the other with a root element ab122.
In this case my map contains only one of the implementing xsd files and I've no idea how to resolve the correct xsd for the incoming xml.
The incoming xml files look like this.
file1.xml:
<ab120 xmlns="http://www.xxxxxxx.com/texxxxxxx" ...>
:
</ab120>
file2.xml
<ab122 xmlns="http://www.xxxxxxx.com/texxxxxxx" ...>
:
</ab122>
The LSResourceResolver interface does not give me access to the xml, so I can't decide according the root node, which xsd I should use.
My temporary solution:
I added a second index with (namespace,xsd_file_name) that resolves correctly when the xml provides the implementing file (systemID)
targenNamespace="namespace myfile.xsd"
My question is, is it correct to specifiy multiple XSD file implementing the same namespace with different xsd structures ?
Edit:
It seemed to be not clear enough. Added two examples
My question is, is it correct to specifiy multiple XSD file implementing the same namespace with different xsd structures ?
Yes, that is a valid use of XML schema. A schema does not have to be represented by a single XSD file. Please see https://www.w3.org/TR/xmlschema-0/#SchemaInMultDocs and https://www.w3.org/TR/xmlschema-0/#import
You may also find this thread helpful: What's the difference between xsd:include and xsd:import?
Ok after asking w3c there is nothing in the specs that precludes this.
Reusing a targetNamespace with different content is allowed.
However, how to handle this, if you have to validate XMLs, is on your own and depends on the situation.
Possible solutions could be adding a version tag to the xml header or combine schemas if possible.
In my context nothing of the above would help, the resolver interface does not allow additional information, and the xsds can not be combined by a choice.
The only way to solve the issue is creating different index, resolver combinations. When creating the validator I have to use the correct resolver according to the origin where the xml came from.
How about including the two existing XSDs in a third one and use this for validation?
schema3.xsd:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema targetNamespace="http://www.xxxxxxx.com/texxxxxxx"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:include schemaLocation="schema1.xsd"/>
<xs:include schemaLocation="schema2.xsd"/>
</xs:schema>

Jaxb. Customize field naming behavior(camelCase to underscore_case)

I want to serialize my fields with underscored names. For example: userName -> user_name.
I know that it can be done with the #XmlElement(name = "user_name") annotation, but it's not very handy for my case.
Is there any way to set up a default naming policy for JAXB?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy has an XMLNameTransformer extension that enables you to override the default naming policy for elements, attributes, and types.
http://blog.bdoughan.com/2011/05/overriding-jaxbs-name-mangling.html
If you generated your model from an XML schema you can use an external binding file to keep the underscores.
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:globalBindings underscoreBinding="asCharInWord"/>
</jxb:bindings>

How to generate JAXB classes using XJC using some existing Java classes?

The scenario is I have a bunch of schemas in .xsd format, which I can generate using XJC. However, I do not like one of the class generated using this approach, as a result, I would like to manually curate a replacement for that specific class. That class is being referenced by other classes in the schema. Is there a way of doing that?
You can use an external binding file to configure XJC to do what you want. In the example below the existing class com.example.Foo will be used for the complex type named Foo.
binding.xml
<jxb:bindings schemaLocation="yourSchema.xsd">
<jxb:bindings node="//xs:complexType[#name='Foo']">
<jxb:class ref="com.example.Foo"/>
</jxb:bindings>
</jxb:bindings>
XJC Call
xjc -d outputDir -b binding.xml yourSchema.xsd
You can manually create the class you have to use jaxb annotaion from javax.xml.bind.annotation package in you class.
below is the link for details of the same.
http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/package-summary.html
but if you can be more specific to your question like what you didnt like in autogenerated classes like class name or package name or anything else that will be a great help to answer this question.
As long as you are annotating the fields/properties with the same values, it is ok to manually change your class and also change any references(including the ObjectFactory class).

JAXB namespace prefixes missing

I have generated Java classes from XSD, all works fine from a unmarshalling point of view.
However, when I marshall from JAXB classes I get the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message xmlns="http://poc.cmc.com/ScreenLayout">
<Data>
<Type>Sample</Type>
. . .
</message>
But I need
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns0:message xmlns:ns0="http://poc.cmc.com/ScreenLayout">
<ns0:Data>
<ns0:Type>Sample</ns0:Type>
. . .
how can I control that from Java?
Thanks a lot
You can use the #XmlSchema annotation on a package-info class to assign a prefix to the namespace:
#XmlSchema(
namespace = "http://poc.cmc.com/ScreenLayout",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns={#XmlNs(prefix="ns0", namespaceURI="http://poc.cmc.com/ScreenLayout")})
package your.package;
import javax.xml.bind.annotation.*;
Cant post this as a comment!
because the consuming application is very dumb and needs the prefix
In that case the dumb application is not really consuming xml. Take a look at this link http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html and play with the namespace options. Specifically
#XmlSchema (
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "ns1", namespaceURI="http:test"),
#javax.xml.bind.annotation.XmlNs(prefix = "xsd", namespaceURI="http:www.w3.org2001XMLSchema")
},
namespace = "http:test",
elementFormDefault = XmlNsForm.UNQUALIFIED,
attributeFormDefault = XmlNsForm.UNSET
)
used in a package-info.java file.
#XmlType(namespace="http://www.example.org/type")
Used on a class declaration
#XmlElement(namespace="http://www.example.org/property")
Used on a property.
Some combination or only one of these options may give you what you want. However you should understand that you're fighting an uphill battle when you move from valid xml to xml that must contain a specific namespace prefix on all elements.
According to XML spec both xml's are the same, as xmlns="" defines default namespace which applies to current and all child elements.
XML parsers should give you the same DOM or SAX in both cases
I did the following steps and everything works. Basically I've compiled form the wsdl or whatever schema file you have.
Download from
https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/ (I've used version 2.3.4)
With the following command:
xjc.sh -wsdl -npa -mark-generated -d src/main/java -p your.package.hierarchy src/main/resources/wsdl/*
I had wsdl files and that's the reason for the first flag, the -npa is to add the namespace information in the annotation rather than on a package-info.java since for some reason that wasn't working for me.

JAXB workaround for Chameleon XSD imports?

this is my first question, so please be gentle ;)
I'm stuck with a weird problem. Essentially i get three XSD definitions like the following:
PartA.xsd
targetNameSpace="PartA"
include="PartB.xsd"
PartB.xsd
<!-- no namespace definition!!! -->
PartC.xsd
targetNameSpace="PartC"
inlude="PartB.xsd"
import="PartA.xsd"
The error pops up, when binding PartC via JAXB to Java classes:
A class/interface with the same name "b.exampleType" is already in use. Use a class customization to resolve this conflict.
This confusing error happened most likely because the schema uses a technique called "chameleon schema", which causes a single definition to be loaded multiple times into different namespaces. See http://forums.java.net/jive/thread.jspa?threadID=18631 for more about this.
Following the link, i found out, the actual error lies in PartB, which has no namespace declaration! This method is called Chameleon Schema. The defined types in PartB will adopt the namesspace of the importing XSD.
So in my case, there are two namespaces for the same type:
"PartA"
"PartC"
And this is, where JAXB breaks down. I haven't found a way to bind PartC properly. And (to make things tricky) i have chance to change the original XSD definitions!
Has anyone come across this phenomena or something like that before and has a valid workaround for it?
I was facing the same problem using wsdl2java:
WSDLToJava Error: Thrown by JAXB : A class/interface with the same
name "Respuesta" is already in use. Use a class customization to
resolve this conflict.
But this question pointed me in the right direction.
Using wsdl2java from CFX you can customize how elements are binded to classes using a binding.xml file.
For example:
/Applications/apache-cxf-2.7.13/bin/wsdl2java -b ./src/main/resources/binding.xml -V -d src/main/java -compile -classdir target/classes http://someurl.wsdl
The key is to explain in the binding.xml to name certain xsd element with one especific className to avoid colissions:
<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="./someXsdFile.xsd">
<!-- Rename the respuesta class to resolve a naming conflict with other Respuesta element already defined-->
<jxb:bindings node="//xs:element[#name='respuesta']/xs:complexType">
<jxb:class name="Respuesta2" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Hope this helps to the next person with this problem using wsdl2java. I supose that other tools should allow similar aproaches to this problem.
I was having the same issue and the google search landed me here.
Your question is detailed enough and I was able to find the answer,
what I did is put the namespace in PartB.xsd and use XJC to generate the java classes.
I added the following:
xmlns:ns="http://www.myCompany.com/2009/01/CustSchema" targetNamespace="http://www.myCompany.com/2009/01/CustSchema"
The following is available, although it does not provide a lot of detail:
https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#compiling-xml-schema-how-modularization-of-schema-interacts-with-xjc
There is one workaround for this problem. More specifically what you have to do is:
1.Define proxy schema (PartB_proxy.xsd) for PartB.xsd (with no namespace definition) and specify temporary namespace (for example PartB):
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns="PartB"
targetNamespace="PartB">
<xsd:include schemaLocation="partB.xsd"/>
2.Prepare bindings file (for large schemas this step could be automatized by generating episode file - more details in my article - I've attached link at the end of this post) - this step is required to avoid generating duplicate classes for PartB schema (by default the duplicate classes that come from PartB schema will be generated for PartA and PartC schemas/java packages):
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<bindings scd="x-schema::partA" xmlns:partA="PartA">
<bindings scd="~partA:SomeType1">
<class ref="SomeType1"/>
</bindings>
<bindings scd="~partA:SomeType2">
<class ref="SomeType2"/>
</bindings>
</bindings>
<bindings scd="x-schema::partC" xmlns:partC="PartC">
<bindings scd="~partC:SomeType1">
<class ref="SomeType1"/>
</bindings>
<bindings scd="~partC:SomeType2">
<class ref="SomeType2"/>
</bindings>
</bindings>
</bindings>
3.Generate JAXB classes using XJC, example Gradle task (I am using Moxy implemetnation but You can use default XJC generator from JDK 8 or standalone JAXB library for newer JDK versions):
task generateExampleChameleonSourcesWithMoxy(type: JavaExec) {
classpath = configurations.moxy
main = 'org.eclipse.persistence.jaxb.xjc.MOXyXJC'
args '-b'
args 'src/main/resources/example/chameleon/bindings.xml'
args '-d'
args 'src/main/generated'
args 'src/main/resources/example/chameleon/PartA.xsd'
args 'src/main/resources/example/chameleon/PartB_proxy.xsd'
args 'src/main/resources/example/chameleon/PartC.xsd'
}
4.Remove proxy namespace (partB) from package-info.java generated for partB schema:
javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package partB;
5.Finally You can marshal and unmarshal these XML documents using the Default Namespace Remapping technique by:
defining the default namespace for the types with no namespace:
com.sun.xml.internal.bind.defaultNamespaceRemap property (JDK JAXB >=JDK 1.8)
com.sun.xml.bind.defaultNamespaceRemap property (External JAXB JDK 1.9+)
performing marshalling/unmarshalling as usual
Here’s the code that is responsible for that (JDK 1.8):
//Initialize JaxbContext
Map<String, String> properties = new HashMap<>();
properties.put("com.sun.xml.internal.bind.defaultNamespaceRemap", "partC");
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{SomeType1.class}, properties);
//Unmarshall Message object file from example XML
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object messageObject = unmarshaller.unmarshal(getClass().getResourceAsStream("/example/chameleon/Division.xml"));
//Marshall message object back into XML
ByteArrayOutputStream xmlMessageOS = new ByteArrayOutputStream();
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(messageObject, xmlMessageOS);
System.out.println(xmlMessageOS.toString());
//Validate output XML with schema
InputStream xmlInputStream = new ByteArrayInputStream(xmlMessageOS.toByteArray());
Source xmlSource = new StreamSource(xmlInputStream);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(getClass().getResource("/example/chameleon/PartC.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlSource);`
Unfortunately, You have to use different JAXB contexts for JAXB objects coming from PartA and PartC namespaces. This is required because JAXB default namespace remapping property is set per JAXB context - this way JAXB marshaller/unmarshaller knows how to deal with POJO objects that have no namespace defined (PartB).
Nevertheless, I do not think it is problematic as usually all the JAXB contexts are initialized once - during the application startup (in singleton).
To sum up, the workaround described above allows You to use JAXB to marshall/unmarshall XML documents without modifying the chameleon schemas. The proxy XSD file is used only at the beginning - for the process of generating JAXB objects (XJC). The marshalled/unmarshalled XML documents still conform to the original schemas. This technique is useful especially if You are not allowed to modify the schemas. I was dealing with that problem for read-only NDC standard (set of schemas) in 18.1 version defined by http://www.iata.org.
I've written an article on that topic: How to deal with Chameleon namespace design in JAXB. You will find it here: https://medium.com/#pziobron/how-to-deal-with-chameleon-namespace-design-in-jaxb-e36bcc03767d. Hopefully, You will find it useful.

Categories

Resources