Enum type erased to string in SOAP WSDL after deployed on JBoss - soap

Here is a SOAP web service. It was initially defined via wsdl/xsd. Then Java classes was generated by Apache CXF. Then a war was built and deployed onto JBoss.
The problem. The wsdl JBoss exposes into the world significantly differs from the one written by me - in the example below custom enum type Fruit was erased into raw string type. As result, there is no type check about the enum - any non empty string value could be "successfully" passed by a client to the service without a schema-not-satisfied error; Java service implementation receives null enum in such cases (although it's a mandatory param).
The question. How prevent such enum type erasure in runtime? Or. How to teach the web service to check requests strictly about enums?
The original definition of the service:
<!-- SOAP WSDL: -->
<wsdl:operation name="pickFruit">
<soap:operation soapAction="http://www.example.com/ws/pickFruit"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<!-- XSD, the request: -->
<xs:element name="pickFruitRequest" type="pickFruitRequest"/>
<xs:complexType name="pickFruitRequest">
<xs:sequence>
<xs:element name="fruit" type="Fruit" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<!-- XSD, the enum: -->
<xs:simpleType name="Fruit">
<xs:restriction base="xs:string">
<xs:enumeration value="orange"/>
<xs:enumeration value="kiwi"/>
<xs:enumeration value="potato"/>
</xs:restriction>
</xs:simpleType>
The WSDL exposed by JBoss:
<!-- http://localhost:8080/example/PickFruitEndpoint?wsdl -->
<xs:complexType name="pickFruitRequest">
<xs:sequence>
<xs:element name="fruit" type="xs:string"/>
</xs:sequence>
</xs:complexType>
UPDATE. Request class auto-generated by CXF:
public class PickFruitRequest {
#XmlElement(required = true)
#XmlSchemaType(name = "string") // it forces type erasure!
protected Fruit fruit;
Although <xs:restriction base="xs:string"> looks like a correct definition for an enum, it turns it leads CXF to add a #XmlSchemaType(name = "string") which leads JBoss to generate a "bad" wsdl in runtime.
JBoss EAP 6.4.0, Spring 4, Apache CXF, Java 7

Related

How to write xsd schema to generate wsdl operations reusing same output type?

I am generating WSDL file from XSD definition using org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition and org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection.
This is definition of response type in XSD schema:
<xs:element name="MyReusableResponse">
<xs:annotation>
<xs:documentation>
<![CDATA[
My reusable response
]]>
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="value1" type="xs:string" />
<xs:element name="value2" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
generated WSDL file then automatically contains operation MyReusable:
<wsdl:operation name="MyReusable">
<wsdl:output message="tns:MyReusableResponse" name="MyReusableResponse" />
</wsdl:operation>
But I would like to have multiple operations using same response element as an output.
<wsdl:operation name="MyReusable">
<wsdl:output message="tns:MyReusableResponse" name="MyReusableResponse" />
</wsdl:operation>
<wsdl:operation name="OtherOperationUsingSameRequest">
<wsdl:output message="tns:MyReusableResponse" name="MyReusableResponse" />
</wsdl:operation>
Is there a way to define custom operation from XSD? Or somehow bind same response type to multiple operations?

What changes should i make in my wsdl file to directly consume in SAP ABAP Proxy?

I have created a soap service using jax-ws in java.I want to consume my WSDL in SAP directly using ABAP proxy. How can i make my WSDL compatible for SAP?
I tried including Max and Min occurrence in my WSDL file. It is working when i test with soap ui. But still getting error in SAP like
SOAP Fault Code:3 One or More Soap header block not understood.
I have searched for this error but couldn't find anything useful.
This is WSDL file which is generated from XSD
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://example.com/soap" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://example.com/soap" targetNamespace="http://example.com/soap">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://example.com/soap">
<xs:element name="getOrderRequest">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="1" name="purchaseOrderNumber" type="xs:long"/>
<xs:element maxOccurs="1" minOccurs="1" name="Type" type="xs:string"/>
<xs:element maxOccurs="1" minOccurs="1" name="vCode" type="xs:string"/>
<xs:element maxOccurs="1" minOccurs="1" name="vName" type="xs:string"/>
<xs:element maxOccurs="1" minOccurs="1" name="Location" type="xs:string"/>
<xs:element name="lineItem" type="tns:lineItem"
maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="lineItem">
<xs:sequence>
<xs:element name="Order_No" type="xs:long"/>
<xs:element name="Material" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="UOM" type="xs:string"/>
<xs:element name="Value" type="xs:decimal"/>
<xs:element name="Tax" type="xs:string"/>
<xs:element name="Item" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
<xs:element name="getOrderResponse">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="1" name="message" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="getOrderRequest">
<wsdl:part element="tns:getOrderRequest" name="getOrderRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getOrderResponse">
<wsdl:part element="tns:getOrderResponse" name="getOrderResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="OrderService">
<wsdl:operation name="getOrder">
<wsdl:input message="tns:getOrderRequest" name="getOrderRequest">
</wsdl:input>
<wsdl:output message="tns:getOrderResponse" name="getOrderResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="OrderServiceSoap11" type="tns:OrderService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getOrder">
<soap:operation soapAction=""/>
<wsdl:input name="getOrderRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getOrderResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="OrderServiceService">
<wsdl:port binding="tns:OrderServiceSoap11" name="OrderServiceSoap11">
<soap:address location="http://localhost:8089/Soap/app/OrderService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
I want to know whether my WSDL file is correct?
Your wsdl policy and service elements are missing. You said that you are getting SOAP header understood error. SOAP header generally used for authentication and generally old SAP version not support authentication in header segment. Change your java code and try with basic authentication.

How Jax-RS used in Restfull Webservices and JAX-WS used in SOAP ?

Jax-ws( Java API for XML webservice)
---- is a set of API for creating a webservices in xml format .
jax-rs (java API used for developer to develop the rest web application easily)
I am trying to understand where exactly this api is used .
Please help me in understand the concept .
SOAP and Restfull Webservices are just standards. They describes how a SOAP/Rest web services should be. For example a SOAP web service call starts with an Envelope and can have a (Soap) Header and (Saop) Body. Also SOAP services calls uses POST http method as default. For more detail, please check SOAP specification and RESTful web services.
So, java communutiy also tries to follows these specifications. But instead just copying these specifications to java environment, they build their api's on the top of these.
Let me try to explain this with an example, lets say you are developing a "Hello, World" service. You want to use SOAP as your service architecture. When you finish designing your service, you probably write your own WSDL document (which is in SOAP specification). In WSDL document you define your object using XML, and also define your service methods with a SOAPAction and operation tag. Like this.
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://helloworld.bahadirakin.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloWorldServiceService" targetNamespace="http://helloworld.bahadirakin.com/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://helloworld.bahadirakin.com/" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://helloworld.bahadirakin.com/">
<xs:complexType name="helloRequest">
<xs:sequence>
<xs:element minOccurs="0" name="firstName" type="xs:string"/>
<xs:element minOccurs="0" name="lastName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="helloRequest" nillable="true" type="helloRequest"/>
<xs:element name="sayHelloResponse" nillable="true" type="xs:string"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="sayHelloResponse">
<wsdl:part element="tns:sayHelloResponse" name="sayHelloResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="sayHello">
<wsdl:part element="tns:helloRequest" name="helloRequest">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="HelloWorldService">
<wsdl:operation name="sayHello">
<wsdl:input message="tns:sayHello" name="sayHello">
</wsdl:input>
<wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloWorldServiceServiceSoapBinding" type="tns:HelloWorldService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="sayHello">
<soap:operation soapAction="sayHello" style="document"/>
<wsdl:input name="sayHello">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="sayHelloResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorldServiceService">
<wsdl:port binding="tns:HelloWorldServiceServiceSoapBinding" name="HelloWorldServicePort">
<soap:address location="http://localhost:8080/camel-soap/HelloWorldInternal"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
In this example we define a service which contains a method named sayHello which gets a parameter of type helloRequest and returns of type sayHelloResponse. And lets look what we defined as sayHelloResponse
<xs:element name="sayHelloResponse" nillable="true" type="xs:string"/>
It is just a string, defined using XML.
But when you change your perspective from XML to JAVA, you won't define your object as XML instead you will use your Classes. Also, you won't define your methods using SOAPAction's or any other xml tag. You just write your methods in JAVA. You will need a framework to make these kind of changes for you. Otherwise you will end up writing your framework to make these kind of change possible. And also, now your are able to define a simple POJO as a SOAP (or Rest) services with just some annotations.
So, JAX-WS and JAX-RS are just names of java standards (apis) for handling SOAP and Restful Service architectures. By using these frameworks you will never worry about how to change a Java method to a web services method. Here is JAX-WS version of the WSDL given above. First lets look at our request parameter helloRequest.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "helloRequest", propOrder = {
"firstName",
"lastName"
})
public class HelloRequest {
protected String firstName;
protected String lastName;
// GETTERS & SETTERS
}
As you can see it is simply a POJO. And now lets look our service interface.
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
#WebService(targetNamespace = "http://helloworld.bahadirakin.com/", name = "HelloWorldService")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface HelloWorldService {
#WebResult(name = "sayHelloResponse", targetNamespace = "http://helloworld.bahadirakin.com/", partName = "sayHelloResponse")
#WebMethod
public java.lang.String sayHello(
#WebParam(partName = "helloRequest", name = "helloRequest", targetNamespace = "http://helloworld.bahadirakin.com/")
HelloRequest helloRequest
);
}
As you can see there is no Envelope, no Body, no HTTP POST or anything else. You just write a java interface and match them with SOAP using JAX-WS API. Yes, you still need to have a basic understanding of what is SOAP. But you can easily develop a SOAP web service thanks to JAX-WS api.
Since JAX-WS and JAX-RS are just APIs, there are different implementation of each api. For example for JAX-WS there are metro, cxf, Axis2 implementations. And for JAX-RS there are jersey, cxf etc. implementations. They fallows same API but implementations are totally different. Also Applications Servers provide their own implementations.
But they still need to convert java object to XML since SOAP specification forces it. There are some other libraries that convert Java to Xml and XML to java. Such as JAXB and XStream. Also, when you develop rest services you probably want to convert your java objects to JSON. There are some tools for that purpose too like Jackson or GSon.
But JAX-RS and JAX-WS are not the only way to develop REST or SOAP web services. For example in order to develop RESTful web services you may use SpringMVC.
"Then, Why should I use a specification" you may ask. It is totally up to you to use a specification or not. Theoretically, If you use a specification, you can change your implementation any time you want. But, since each different implementations provides different cool features, you probably end up a highly coupled application. So you may not change that easily.

Mule & Eclipse's WSDL issue

so I have implemented a very simple webservice using eclipse and generated its WSDL using the CXF which is the framework used in Mule as well. However, when I try to publish that same service in Mule using the previously generated WSDL it stops due to something like "BadUsageException: -p invalid character" which is comes from the CXF. I have tried to the java classes from mule using an Axis generated WSDL but no luck with the CXF generated.
Here is my wsdl:
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://snippet/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="SnippetService" targetNamespace="http://snippet/">
<wsdl:types>
<xs:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://snippet/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" elementFormDefault="unqualified" targetNamespace="http://snippet/" version="1.0">
<xs:element name="multiply" type="tns:multiply"/>
<xs:element name="multiplyResponse" type="tns:multiplyResponse"/>
<xs:element name="sum" type="tns:sum"/>
<xs:element name="sumResponse" type="tns:sumResponse"/>
<xs:complexType name="sum">
<xs:sequence>
<xs:element name="arg0" type="xs:int"/>
<xs:element name="arg1" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="sumResponse">
<xs:sequence>
<xs:element name="return" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="multiply">
<xs:sequence>
<xs:element name="arg0" type="xs:int"/>
<xs:element name="arg1" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="multiplyResponse">
<xs:sequence>
<xs:element name="return" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="multiplyResponse">
<wsdl:part element="tns:multiplyResponse" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:message name="sumResponse">
<wsdl:part element="tns:sumResponse" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:message name="sum">
<wsdl:part element="tns:sum" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:message name="multiply">
<wsdl:part element="tns:multiply" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:portType name="InterNya">
<wsdl:operation name="sum">
<wsdl:input message="tns:sum" name="sum"></wsdl:input>
<wsdl:output message="tns:sumResponse" name="sumResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="multiply">
<wsdl:input message="tns:multiply" name="multiply"></wsdl:input>
<wsdl:output message="tns:multiplyResponse" name="multiplyResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SnippetServiceSoapBinding" type="tns:InterNya">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="sum">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="sum">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="sumResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="multiply">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="multiply">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="multiplyResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SnippetService">
<wsdl:port binding="tns:SnippetServiceSoapBinding" name="SnippetPort">
<soap:address location="http://localhost:8080/hassib/services/SnippetPort"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Any help would be appreciated. Thanks.
Tested your WSDL with the Anypoint Studio July 2014 Release.
It correctly creates the Web Service classes you expect.
I used JavaSE-1.7 and a 3.5.1 Mule engine.
How I did it:
1. Drag a HTTP endpoint into a new flow
2. Drag a CXF endpoint behind
3. Open CXF properties and create the java classes using "Generate from WSDL" at the Service class property
Cheers,
Patrick

How to reference an element in and XSD and give it a new name?

I need to re use a status tag that I created in an XSD. For example in our order company we have several statuses. Status of an order- car order, truck order etc.
The tags that need to be used are unfortunately not the same. For the car it is a carStatus and for the truck it is a truckStatus but the underlying object are the same. It is a xs:string tag that has an enumeration of COMPLETED, BUSY or AWAITING INFORMATION.
Now I don not want to have 16 tags for 16 objects (car, track, chopper... -Status). Tomorrow if we add another status I have to go to all of these elements and update it.
My XSD where I reference the GenericCodeStatus looks as follows
<xs:schema targetNamespace="http://www.myDomain.co.za/myCoreXsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mine="http://www.myDomain.co.za/myCoreXsd" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- Defining my Enum -->
<xs:element name="GenericCodeStatus">
<xs:annotation>
<xs:documentation>Generic code status</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="COMPLETED"/>
<xs:enumeration value="BUSY"/>
<xs:enumeration value="AWAITING INFORMATION"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<!-- Here I have mytag where I am referencing the genericCodeStatus -->
<xs:complexType name="MyTag1">
<xs:sequence>
<xs:element ref="mine:GenericCodeStatus"/>
</xs:sequence>
</xs:complexType>
Now the thing is that I want to have the genericCodeStatus under MyTag1 to have a name.
I tried creating it with a name and type tag (and i am using XML Spy as an editor)
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.myDomain.co.za/myCoreXsd" xmlns:mine="http://www.myDomain.co.za/myCoreXsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- Defining my Enum -->
<xs:element name="GenericCodeStatus">
<xs:annotation>
<xs:documentation>Generic code status</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="COMPLETED"/>
<xs:enumeration value="BUSY"/>
<xs:enumeration value="AWAITING INFORMATION"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:complexType name="MyTag1">
<xs:sequence>
<!-- Taken this out -->
<xs:element ref="mine:GenericCodeStatus"/>
<!-- and replace it with name and type -->
<xs:element name="carStatus" type="mine:GenericCodeStatus"/>
</xs:sequence>
</xs:complexType>
But then get an error of an undefined value for 'type' encountered error.
I have also tried removing the 'mine' namespace.
If I try to replace the type with a ref as in
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://www.myDomain.co.za/myCoreXsd" xmlns:mine="http://www.myDomain.co.za/myCoreXsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- Defining my Enum -->
<xs:element name="GenericCodeStatus">
<xs:annotation>
<xs:documentation>Generic code status</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="COMPLETED"/>
<xs:enumeration value="BUSY"/>
<xs:enumeration value="AWAITING INFORMATION"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:complexType name="MyTag1">
<xs:sequence>
<!-- Taken this out -->
<xs:element ref="mine:GenericCodeStatus"/>
<!-- and replace it with name and ref -->
<xs:element name="carStatus" ref="GenericCodeStatus"/>
</xs:sequence>
</xs:complexType>
The validation works fine but if I save it XML Spy is removing the name element and I am back to where I started.
If anyone knows please?
I found the answer to this but thought of still posting this as it was difficult to find. Thanks to a buddy of mine :)
I should not define the Element like I did and then try to reference it over and over each time with a new name.
What I should do is to define the simpleType on its own and give it a name.
<!-- Define the simpleType as an enum and give it a name -->
<xs:simpleType name="myCoolDataType">
<xs:restriction base="xs:string">
<xs:enumeration value="COMPLETED"/>
<xs:enumeration value="BUSY"/>
<xs:enumeration value="AWAITING INFORMATION"/>
</xs:restriction>
</xs:simpleType>
Then where I want to use it I need to define the element and just give it a type with the value you gave to the enum in the first stip
<xs:complexType name="MyTag1">
<xs:sequence>
<xs:element name="truckStatus" type="mine:myCoolDataType"/>
<xs:element name="carStatus" type="mine:myCoolDataType"/>
</xs:sequence>
</xs:complexType>