spring ws soap client+jaxb2 - java

I am using the JAXb2 maven plugin to create the domain[bean ]classes.
When i try to hit the service thru WebServiceTemplate class, I am getting below error.
Exception:org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"http://services.abc.cde.efg.com", local:"xxxLookupResponse"). Expected elements are <{services.abc.cde.efg.com"}xxxLookupRequest>,<{services.abc.cde.efg.com"}xxxLookupResponse>,<{services.abc.cde.efg.com"}zzzUploadOrder>
and my bindings file looks as follows.
I am wondering how is it expecting three elements, that too the last one is not at all related with this webservice and not defined in jaxb binding file also. I have checked the created bean classes and they are not interrelated.
<jaxb:bindings schemaLocation="abcsServices.xsd" node="/xs:schema">
<jaxb:bindings node="xs:complexType[#name='xxxxxLookupRequest']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement"
name="xxxxxxLookupRequest" />
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="abcsServices.xsd" node="/xs:schema">
<jaxb:bindings node="xs:complexType[#name='xxxxxLookupResponse']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement"
name="xxxxxLookupResponse" />
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
Please throw some light on this. I am stuck here.
Client code:
ObjectFactory objFactory = new ObjectFactory(); xxxxLookupRequest req = objFactory.createxxxxLookupRequest(); req.setxxxx("12344"); req.setxxxxx("34234"); xxxxxLookupResponse response = (xxxxxLookupResponse) xxxxClient .doDeliveryLookUp(req);
========
spring client code:
response = (xxxxxLookupResponse) getWebServiceTemplate() .marshalSendAndReceive(xxxxLookupRequest, new SoapActionCallback("urn:xxxxxLookup"));

How do you create your JAXBContext? Please show the Spring configuration.
The error message is also weird:
...unexpected element (uri:"http://services.abc.cde.efg.com", local:"xxxLookupResponse"). Expected elements are ... <{services.abc.cde.efg.com"}xxxxxLookupResponse>...
Do you have matching names (xxxLookupResponse vs. xxxxxLookupResponse) here?
My theory is that you have one package (services.abc.cde.efg.com) generated or defined in two places and JAXB is picking the wrong one.
The binding files you refer to are not directly considered by JAXB, they are only used during the code generation. JAXB works with the generated classes then.

Related

JAXB binding to annotate all strings in all schemas under /schema with a custom annotation

I have a dir /schemas that has many .xsd files, and I want to annotate every field of type String with a custom annotation I created.
I'm using this plugin: "org.jvnet.jaxb2_commons:jaxb2-basics-annotate:0.6.4".
I think creating a jaxb binding config would be my ideal solution. I tried this:
<jaxb:bindings>
<jaxb:bindings node="xs:element[#type='xs:string']">
<annox:annotateClass>#com.myapp.model.CustomAnnotation</annox:annotateClass>
</jaxb:bindings>
</jaxb:bindings>
But in vain. Can you help? Thank you

Customize object/element name with JAXB

I'm very new to JAXB, so I'm having trouble cracking this (I assume) very simple use case.
I have a set of schemas I got. I have no control over those, I cannot change them. In these schemas, I have declarations such as
<xs:complexType name="CustomerType">
...
I try to generate classes from these. So such a declaration becomes
#XmlType(name = "CustomerType", propOrder = {
"field1",
"field2"
})
public class CustomerType {
...
Then I need to use this class to create XML messages using a RestTemplate. The problem is, the object in the XML message is not supposed to be "CustomerType", it's supposed to be just "Customer". Like I said, I cannot edit the schemas. I also cannot directly edit the generated sources. I need some kind of external customization that tells either the source generating process, or the marshalling process, how to transform the names of the objects. Any advice will be greatly appreciated.
You can use bindings to customize class or property names. Typically you'll have a file like bindings.xjb like this:
<jaxb:bindings version="1.0" xmlns:jaxb="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"
jaxb:extensionBindingPrefixes="xjc">
<jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
<jaxb:bindings node="xsd:customType[#name='CustomerType']">
<jaxb:class name="Customer"/>
</jaxb:bindings>
<jaxb:bindings node="xsd:customType[#name='CustomerType']//xsd:element[#name='field1']">
<jaxb:property name="f1"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
There are quite a few things you can customize with bindings (see this), but certainly not everything.
The way DTO objects are created is:
You define all the types at one place like: CustomerType, UserType, OrderType and so on.
You then create another schema and import appropriates XSD's within where you have defined multiple types. Then you actually use/aggregate these type definitions to create your XML Schema for objects . Something like below
<xs:complexType name="CustomerOrders">
<xs:element name="Customer" type="CustomerType">
<xs:attribute name="Orders" type="OrderType">

XML & JAXB: pass attribute into value

I have a large amount of objects generated through JAXB (maven-jaxb2-plugin) and annotate them with the jaxb2-annotate-plugin. These classes may define a RelationType and I'd like to annotate them with the corresponding #RelationType annotation. I use an XPath expression to find the name attribute in the XSD and annotate the class, passing its specific type into the annotation. An example of this is the following:
<jaxb:bindings node="//xsd:complexType[#name='SomeRelationType']">
<annox:annotate target="class">#com.example.RelationType(type = "SomeRelationType")</annox:annotate>
</jaxb:bindings>
which maps on the following XSD snippet:
<xsd:complexType name="SomeRelationType">
<xsd:complexContent>
<xsd:extension base="RelationType">
<xsd:sequence>
<xsd:element name="someValue" type="SomeValue"/>
<xsd:element name="otherValue" type="OtherValue"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
I find the ComplexType with the SomeRelationType name and annotate the class with a #RelationType annotation, which has the SomeRelationType as its type parameter. It would generate the following class:
#RelationType(type = "SomeRelationType")
public class SomeRelationType extends RelationType implements Serializable {
private final static long serialVersionUID = 1L;
protected SomeValue someValue;
protected OtherValue otherValue;
}
This works fine if it were just a few domain objects. But I have a large amount and defining every annotation manually is not only tedious but also bad in terms of change and expansion.
To generify it, I can rewrite the XPath expression to the following:
<jaxb:bindings node="//xsd:complexType[substring(#name, string-length(#name) - string-length('RelationType') + 1)]" multiple="true">
<annox:annotate target="class">#com.example.RelationType(type = "SomeRelationType")</annox:annotate>
</jaxb:bindings>
The problem: The type parameter of my annotation is still defined as "SomeRelationType". It would be great if I could use the same #name as defined in the XPath expression. Then all the classes whose name ends with "RelationType" also automatically gets its #RelationType annotation with the correct type parameter.
It doesn't work as simple as doing the following of course, but it shows what I'd like to achieve:
<jaxb:bindings node="//xsd:complexType[substring(#name, string-length(#name) - string-length('RelationType') + 1)]" multiple="true">
<annox:annotate target="class">#com.example.RelationType(type = #name)</annox:annotate>
</jaxb:bindings>
Is such a thing even possible or is this impossible in XML/JAXB?
But I have a large amount and defining every annotation manually is not only tedious but also bad in terms of change and expansion.
For me, #com.example.RelationType(type = "SomeRelationType") looks like a trivial metainformation which could be derived via reflection without any annotations. So check if there's a way to do "convention over configuration" thing.
The jaxb2-annotate-plugin does not and will not support parameterization, it would be too narrow and too complex to implement. Disclaimer I'm the author of the jaxb2-annotate-plugin.
I see two options:
Pre-generate bindings in your build. XML Schema is XML so writing XSLT to produce bindings files should not be too complicated.
Write an own XJC plugin to add annotations as you want them.
Bribe me to add parameterization to the jaxb2-annotate-plugin.
Right, just two options.

JAXB binding multiple files with same namespace to same package

I'm having a schema hierarchy like this:
common
|---legacy
| |---legacy.xsd xmlns="http://common/legacy"
| |---other.xsd xmlns="http://common/legacy"
| '---....xsd xmlns="http://common/legacy"
|---send
|---file.xsd xmlns="http://common/send"
'---text.xsd xmlns="http://common/send"
'---....xsd xmlns="http://common/send"
All files in one folder have the same namespace.
Now I want to map the namespaces to specific java packages (I cannot change the namespace).
I found a solution to bind a schema to a package. But then I would have to create one entry per xsd-file:
<jaxb:bindings schemaLocation="./common/legacy/legacy.xsd">
<jaxb:schemaBindings>
<jaxb:package name="com.company/legacy"/>
</jaxb:schemaBindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="./common/legacy/other.xsd">
<jaxb:schemaBindings>
<jaxb:package name="com.company/legacy"/>
</jaxb:schemaBindings>
</jaxb:bindings>
.....
Is there a way to directly define a binding between namespace and a package name?
The other way would be to define the package in maven:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<configuration>
<generatePackage>com.company/legacy</generatePackage>
</configuration>
</plugin>
But then I would have to create one execution per folder, which is not really what I want.
Disclaimer: I'm the author of maven-jaxb2-plugin.
XJC derives packages from namespaces, so you (normally) can't generate several packages for one namespace. There are a few tricks with jaxb:class/#ref but you don't want those as this may lead to all kinds of collisions.
So my suggestion would be to define multiple executions, one per distinct schema in the same namespace. You could use generatePackage although I generally advise to define package mappings in bindings instead.
When doing multiple executions, make sure you use distinct generateDirectory per execution.
By the way, why are you not comfortable with multiple bindings?
Use scd syntax instead node="XPath" schemaLocation="path or *":
<jaxb:bindings scd="x-schema::tns" xmlns:tns="http://common/legacy">
<jaxb:schemaBindings>
<jaxb:package name="com.company.legacy"/>
</jaxb:schemaBindings>
</jaxb:bindings>
SCD is not supported everywhere. Some XJC Customizations, like the jaxb2-basics, not working in jaxb:bindings.
JAXB RI 2.1 User guide
Schema Component Designator - recommendation

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

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.

Categories

Resources