I have a JAXB-annotiated class with some required fields:
...
#XmlElement(required = true, nillable = false)
private String credentials = null;
...
Using SoapUI, the generated wsdl is like this:
...
<xs:element name="credentials" type="xs:string"/>
...
Is there any way to get the required-information into the wsdl? If I understood this right, than the wsdl should look like this (maybe that):
...
<xs:element wsdl:required="true" name="credentials" type="xs:string"/>
...
#XmlElement(required=true) corresponds to an element in the XML Schema with the attribute minOccurs="1". Since this the default it is not required to be specified.
Related
i am pretty new to zeep, and soap. i`am trying to make client request to soap ws function. wsdl of function:
-<s:element name="GetRetailTransactions">
-<s:complexType>
-<s:sequence>
-<s:element name="parameters" maxOccurs="1" minOccurs="0">
-<s:complexType mixed="true">
-<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
i dont fully understand how to create object with type any in zeep.
i have tried :
wsdl = 'http://domain/app.asmx?WSDL'
client = Client(wsdl=wsdl)
params = {
'RetailTransactionsParameters': {
'GetNotExportedOnly': '0',
'GetNotRetrunsOnly': '0',
'FromDate': '20170518',
'ToDate': '20170518',
'TransactionTypeFilter': {
'TransactionType': '2'
},
},
}
parameters = client.get_element('ns0:GetRetailTransactions')
param = xsd.AnyObject(parameters, parameters(params))
result = client.service.GetRetailTransactions(param)
but i get error:
File "/home/user/lib/python3.6/site-packages/zeep/xsd/elements/indicators.py", line 227, in render
if name in value:
TypeError: argument of type 'AnyObject' is not iterable
on soapui i can make request and successfully get answer with :
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<GetRetailTransactions xmlns="example.com/">
<parameters>
<RetailTransactionsParameters>
<GetNotExportedOnly>0</GetNotExportedOnly>
<GetNotRetrunsOnly>0</GetNotRetrunsOnly>
<FromDate>20170518</FromDate>
<ToDate>20170518</ToDate>
<TransactionTypeFilter>
<TransactionType>2</TransactionType>
</TransactionTypeFilter>
</RetailTransactionsParameters>
</parameters>
</GetRetailTransactions>
</Body>
</Envelope>
maybe someone can guide me how to correctly make such a request with zeep..
thanks in advance
I had the same problem today. The get_element method returns the type. To create the object you need to instantiate it. You can either do:
parameters = client.get_element('ns0:GetRetailTransactions')(params)
or you can explicitly set each property:
parameters = client.get_element('ns0:GetRetailTransactions')()
parameters.GetNotExportedOnly = 0
parameters.GetNotRetrunsOnly = 0
...
or you can pass the dict object and zeep does the conversion to the type
http://docs.python-zeep.org/en/master/datastructures.html#creating-objects
In order to marshal jaxb classes with Apache Camel the jaxb class needs to include a XmlRootElement annotation.
When generating jaxb classes from XSD the XmlRootElement annotation might not be generated.
This will lead to an Exception during marshalling
"No type converter available to convert from type: "
As soon as I add the #XmlRootElement manually, everything works fine, but since these Jaxb classes are generated, adding the anntotation manually is no option.
According to the Camel documentation in such a case, the JaxbDataFormat can be set to 'fragement(true)
JaxbDataFormat jaxbMarshal = new JaxbDataFormat();
jaxbMarshal.setContextPath(ObjectFactory.class.getPackage().getName());
jaxbMarshal.setFragment(true);
Unfortunately I still get the same exception.
Is there a way to configure JaxbDataFormat different, i.e. to define the JAXBElement which is the root element, like I would do in Java
marshaller.marshal( new JAXBElement( new QName("uri","local"),
MessageType.class, messageType ));
or is there another strategy available to get the XML marshalled?
EDIT
the used route :
from("file://inbox").unmarshal(jaxbDataFormat)
.marshal(jaxbDataFormat).to("file://outbox");
the stacktrace:
java.io.IOException: org.apache.camel.NoTypeConversionAvailableException: No type converter
available to convert from type: com.xyz.AddressType to the required
type: java.io.InputStream with value com.xyz.AddressType#32317e9d at
org.apache.camel.converter.jaxb.JaxbDataFormat.marshal(JaxbDataFormat.java:148)
~[camel-jaxb-2.16.0.jar:2.16.0] at
org.apache.camel.processor.MarshalProcessor.process(MarshalProcessor.java:83)
~[camel-core-2.16.0.jar:2.16.0] at
...
[na:1.8.0_25] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: org.apache.camel.NoTypeConversionAvailableException: No
type converter available to convert from type: com.xyz.AddressType to
the required type: java.io.InputStream with value
com.xyz.AddressType#32317e9d at
org.apache.camel.impl.converter.BaseTypeConverterRegistry.mandatoryConvertTo(BaseTypeConverterRegistry.java:185)
~[camel-core-2.16.0.jar:2.16.0] at
...
In Camel 2.17, the #XmlRootElement was not required. As of 2.21, it is. Unless...
The class org.apache.camel.converter.jaxb.FallBackTypeConverter changed it's implementation from:
protected <T> boolean isJaxbType(Class<T> type) {
return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
}
To:
protected <T> boolean isJaxbType(Class<T> type) {
if (isObjectFactory()) {
return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
} else {
return hasXmlRootElement(type);
}
}
By default the isObjectFactory() method returns false. If you set the property CamelJaxbObjectFactoryon your CamelContext to true. then the JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) will return true and the deserialization works again as before without the need for an #XmlRootElement. For completeness:
<camelContext xmlns="http://camel.apache.org/schema/spring" id="camelContext">
<properties>
<property key="CamelJaxbObjectFactory" value="true"/>
</properties>
</camelContext>
I experienced the equivalent behaviour with JaxB (#XmlRootElement annotation not present in the generated class), and I suppose it comes from the way the root element is defined in the XML schema.
For example:
<xsd:element name="DiffReport" type="DiffReportType" />
<xsd:complexType name="DiffReportType">
...
</xsd:complexType>
it will generate you the DiffReportType class without the #XmlRootElement annotation. But if you directly define your root element as following, you'll get the annotation set in your generated class (the name of the root class is then DiffReport in my example).
<xsd:element name="DiffReport">
<xsd:complexType>
...
Note: I used the first way to define the complex types in my schema for class name consistency.
You can use the "partClass" option of the jaxb data format of camel. Your question is answered in the camel docs for jaxb, which describes how to marshall XML fragments (or XML generated without the XmlRootElement annotation).
Use partClass and provide the actual class name to which you wish to marshall. In case of marshalling you also have to provide the partNamespace which is the target namespace of the desired XML object.
I have an exception:
public class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
The exception is thrown from a webservice method.
When I generate the Webservice using a regular Jax-ws implementation, the WSDL has:
<xs:complexType name='MyException'>
<xs:sequence>
<xs:element minOccurs='0' name='message' type='xs:string' />
</xs:sequence>
</xs:complexType>
But, when generating the webservice with cxf, I get:
<xs:complexType name='MyException'> <xs:sequence/></xs:complexType>
Which is not ok for me: I expect to get the first variant.
Can you please advise how to force CXF to provide the desired result?
Remark: I cannot alter the code in the exception! The Exception does not have any fields!
Thanks!
This is already reported and fixed in the latest CXF versions:
https://issues.apache.org/jira/browse/CXF-4748
Getting following error while unmarshalling a response String(in xml format). Initially it was complaining about the and ,so I removed the soap part from the response.Now it comes up with this error.
Classes are created from provided WSDL using JAXB 2
**javax.xml.bind.UnmarshalException: unexpected element (uri:"http://ws.taxwareenterprise.com", local:"calculateDocumentResponse"). Expected elements are (none)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:662)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:258)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:253)**
Here is my response string (part of it)
**<calculateDocumentResponse xmlns="http://ws.taxwareenterprise.com">
<txDocRslt>
<jurSumRslts>
<jurSumRslt>
<xmptAmt>5.0</xmptAmt>
<txableAmt>15.0</txableAmt>
<txAmt>0.04</txAmt>
<txJurUID>...**
Here goes my xsd for "CalculationResponse"(part of it)
<xs:complexType name="CalculationResponse">
<xs:sequence>
<xs:element name="txDocRslt" type="tns:TxDocRslt"/>
</xs:sequence>
</xs:complexType>
and this is my code for unmarshalling:
**final JAXBContext context = JAXBContext.newInstance(CalculationResponse.class);
final Unmarshaller unmarshaller = context.createUnmarshaller();
response = processResponse(response);//for removing soap headers
responseObj = (CalculationResponse) unmarshaller.unmarshal(new StringReader(response));//Fails here...
final TxDocRslt txDocRslt = responseObj.getTxDocRslt();**
I'm currently using Zend_Soap_AutoDiscover to generate my WSDL file, the problem is I want this wsdl to handle output of type ArrayOfString ( string[] ). so I changed the complex type strategy to Zend_Soap_Wsdl_Strategy_ArrayOfTypeSequence, it works properly but the problem is that the output isn't really an array of string the output xml is somthing like this :
<xsd:complexType name="ArrayOfString">
<xsd:sequence>
<xsd:element name="item" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
But I want output like this :
<xsd:complexType name="ArrayOfstring">
<xsd:complexContent>
<xsd:restriction base="soapenc:Array">
<xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
so ,I used the new strategy , Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex, but the problem is that this strategy does not handle string[].
Finally -> What should I do :D?!
Try creating a response class that has just one attribute, as follows:
class Response
{
/** #var string[] */
public $items;
}
Then define your service class to return an object of type Response, as follows:
class Service
{
/**
* #param string
* #return Response
*/
public function process( $input )
{
$response = new Response();
// Populate $response->items[] object with strings...
return $response;
}
}
Then use the 'Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex' strategy when using Zend_Soap_Autodiscover to create the WSDL. Although this probably won't produce precisely the output you're after, it should produce something that is semantically closer than what you're currently getting. The key with this approach is to get the PHPDoc right.
If that still doesn't work, post the key bits of your code, as that will help resolve the issue more quickly.