Unmarshalling soap response to java object - java

Below is the SOAP Response that need to convert to Java Objects
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns0:HelpDesk_Query_ServiceResponse xmlns:ns0="urn:XXXX_HPD_IncidentInterface_WS__XXXXX" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Assigned_Group>TIM-CSDWINDOWS-ADMIN</ns0:Assigned_Group>
<ns0:Assigned_Group_Shift_Name/>
<ns0:Assigned_Support_Company>India Ltd</ns0:Assigned_Support_Company>
<ns0:Assigned_Support_Organization>TIM-CSD</ns0:Assigned_Support_Organization>
<ns0:Assignee>Akshay Patwardhan</ns0:Assignee>
<ns0:Categorization_Tier_1>TIM</ns0:Categorization_Tier_1>
<ns0:Categorization_Tier_2>ATT</ns0:Categorization_Tier_2>
<ns0:Categorization_Tier_3>C Drive Enablement</ns0:Categorization_Tier_3>
<ns0:City>HYDERABAD</ns0:City>
<ns0:Closure_Manufacturer/>
<ns0:Closure_Product_Category_Tier1/>
<ns0:Closure_Product_Category_Tier2/>
<ns0:Closure_Product_Category_Tier3/>
<ns0:Closure_Product_Model_Version/>
<ns0:Closure_Product_Name/>
<ns0:Company>India Ltd</ns0:Company>
<ns0:Contact_Company>India Ltd</ns0:Contact_Company>
<ns0:Contact_Sensitivity>Standard</ns0:Contact_Sensitivity>
<ns0:Country>India</ns0:Country>
<ns0:Department>TIM-India </ns0:Department>
<ns0:Summary>Test</ns0:Summary>
<ns0:Notes>Host Name: INHYTZPC03456 Detailed Business Justification: test Project/ODC Name: TIM Your Current Location Details: </ns0:Notes>
<ns0:First_Name>Venkata</ns0:First_Name>
<ns0:Impact>4-Minor/Localized</ns0:Impact>
<ns0:Last_Name>Sabbarapu</ns0:Last_Name>
<ns0:Manufacturer/>
<ns0:Middle_Initial/>
<ns0:Organization>XXX_TIM</ns0:Organization>
<ns0:Phone_Number>XXXXXX Extn: 67 -XXXXXX</ns0:Phone_Number>
<ns0:Priority>Medium</ns0:Priority>
<ns0:Priority_Weight>10</ns0:Priority_Weight>
<ns0:Product_Categorization_Tier_1/>
<ns0:Product_Categorization_Tier_2/>
<ns0:Product_Categorization_Tier_3/>
<ns0:Product_Model_Version/>
<ns0:Product_Name/>
<ns0:Region>India</ns0:Region>
<ns0:Reported_Source>Self Service</ns0:Reported_Source>
<ns0:Resolution/>
<ns0:Resolution_Category/>
<ns0:Resolution_Category_Tier_2/>
<ns0:Resolution_Category_Tier_3/>
<ns0:Service_Type>User Service Request</ns0:Service_Type>
<ns0:Site>BHD-SEZ</ns0:Site>
<ns0:Site_Group>HYDERABAD</ns0:Site_Group>
<ns0:Status>Assigned</ns0:Status>
<ns0:Status_Reason xsi:nil="true" />
<ns0:Urgency>3-Medium</ns0:Urgency>
<ns0:VIP>No</ns0:VIP>
<ns0:ServiceCI/>
<ns0:ServiceCI_ReconID/>
<ns0:HPD_CI/>
<ns0:HPD_CI_ReconID/>
<ns0:HPD_CI_FormName/>
<ns0:z1D_CI_FormName/>
</ns0:HelpDesk_Query_ServiceResponse>
</soapenv:Body>
</soapenv:Envelope>
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
String Assigned_Group;
String Assigned_Group_Shift_Name;
String Assigned_Support_Company;
String Assigned_Support_Organization;
String Assignee;
String Categorization_Tier_1;
String Categorization_Tier_2;
String Categorization_Tier_3;
String City;
public String getAssigned_Group() {
return Assigned_Group;
}
public void setAssigned_Group(String assigned_Group) {
Assigned_Group = assigned_Group;
}
public String getAssigned_Group_Shift_Name() {
return Assigned_Group_Shift_Name;
}
public void setAssigned_Group_Shift_Name(String assigned_Group_Shift_Name) {
Assigned_Group_Shift_Name = assigned_Group_Shift_Name;
}
public String getAssigned_Support_Company() {
return Assigned_Support_Company;
}
This is UnMarshall code
Unmarshaller unmarshaller = JAXBContext.newInstance(Response.class).createUnmarshaller();
Document bodyDoc = soapResponse.getSOAPBody().extractContentAsDocument();
Response request = (Response) unmarshaller.unmarshal(bodyDoc);
its giving javax.xml.bind.UnmarshalException.
Can some help me in creating Java POJO and UnMarshall the above soap XML response to java Object.

I recommend to use wsimport to generate SOAP clients. There is also a Maven Plugin.

Or the tools wsdl2java , it will create the classes for you. Use the tools of your soap stack (cxf, axis2...)

Related

I am not getting how to set the request for XML in WSDL service call

I am integrating with third party vendor where they have exposed SOAP apis. I am having issue while creating the request.
The below is WSDL generated code of vendor wsdl file.
Usually what we do is we create xml fields and then sent it, But in this case it has some XMLrequest where i need to set the request. I googled but didnt get the solution.
The below is WSDL generated code of vendor wsdl file.
Usually what we do is we create xml fields and then sent it, But in this case it has some XMLrequest where i need to set the request. I googled but didnt get the solution.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"xmlRequest"
})
#XmlRootElement(name = "GetAuthenticationToken")
public class GetAuthenticationToken {
protected GetAuthenticationToken.XmlRequest xmlRequest;
public GetAuthenticationToken.XmlRequest getXmlRequest() {
return xmlRequest;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"content"
})
public static class XmlRequest {
#XmlMixed
#XmlAnyElement(lax = true)
protected List<Object> content;
public List<Object> getContent() {
if (content == null) {
content = new ArrayList<Object>();
}
return this.content;
}
}
}
How do I set the XmlRequest which has request something like this.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:GetAuthenticationToken>
<!--Optional:-->
<tem:xmlRequest>
<parent>
<A>ffd</A>
<B>57</B>
<C>2</C>
<D>12</D>
</parent>
</tem:xmlRequest>
</tem:GetAuthenticationToken>
</soap:Body>
</soap:Envelope>
Please let me know if didn't understood the problem statement.

How to unmarshall SOAP message created by .NET Soap Formatter through JAXB

I have a SOAP message made in C# through SOAP Formatter:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:Artifact id="ref-1" xmlns:a1="artifactNamespace">
<code id="ref-4">TestCode</code>
<exam href="#ref-14"/>
</a1:CrfArtifact>
<a4:Exam id="ref-14" xmlns:a4="examNamespace">
<name id="ref-20">TestExam</name>
</a4:Exam>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I'm trying to create correct Java strongly typed obect which would follow this message. In C# I have hierarhy:
Artifact
|
------Exam
I want to have the same in Java. As you see in SOAP message formatter places Artifact and Exam on the same level and links them through href->ref relation. My Question is how to create such data model which could properly deserialize this message into Java objects with mentioned hierarchy.
My Envelope:
#XmlRootElement(name="Envelope")
#XmlAccessorType(XmlAccessType.FIELD)
public class Envelope {
#XmlElement(name="Body")
public Body body;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Body {
#XmlElement(name="Artifact")
public generated.Artifact artifact;
}
My Java data classes:
#XmlAccessorType(XmlAccessType.FIELD)
public class Artifact {
#XmlElement(name="code")
public String examcode;
#XmlElement(name="exam")
public Exam exam;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Exam {
#XmlAttribute(name="id")
#XmlID
public String examid;
#XmlElement(name="name")
public String examname;
}
I used NamespaceFilter to get rid of namespaces to make things more clear, by my Exam node is not picked up by unmarshaller and is always null:
public static void Unmarshal() throws JAXBException, SAXException, FileNotFoundException {
//Create context for my message
JAXBContext jaxbContext = JAXBContext.newInstance(Envelope.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// Create an XMLReader to use the namespace filter
XMLReader reader = XMLReaderFactory.createXMLReader();
// Create the filter (to add namespace) and set the xmlReader as its
// parent.
NamespaceFilter inFilter = new NamespaceFilter(null, false);
inFilter.setParent(reader);
// Prepare the input
InputSource is = new InputSource(new FileInputStream("src/main/resources/input.xml"));
// Create a SAXSource specifying the filter
SAXSource source = new SAXSource(inFilter, is);
// Do unmarshalling
Envelope myJaxbObject = (Envelope) jaxbUnmarshaller.unmarshal(source);
}
The result:
Any help is apritiate. Thanks

JAX-WS Handler Ignoring Fault Sub-elements

I'm implementing a web service client using JAX-WS over SOAP. Its error codes are returned in the following way:
<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<env:Header>
<!-- header stuff goes here -->
</env:Header>
<env:Body>
<env:Fault>
<abc:fault xmlns:abc="http://example.com/abc">
<abc:faultcode>12345</abc:faultcode>
<abc:faultstring>Error message goes here</abc:faultstring>
</abc:fault>
</env:Fault>
</env:Body>
</env:Envelope>
As far as I know, this is not the correct way to do SOAP faults. The subelements of a env:Fault should be <faultcode> and <faultstring>, not a different namespaced <fault>. Unfortunately, I have no way of making the web service change this.
My hope was that I would be able to parse this message in a SOAPHandler and transform it into a regular fault before passing it on to the rest of my code, however when I logged the message in an earlier Handler I saw that the Fault element completely empty. The <abc:fault> was gone!
I'm using JAX-WS on WebSphere 7 and I've tried setting "jaxws.payload.highFidelity" to true in my system properties. Any clues on to how to get at the original message?
Leaving this alone will cause a WebServiceException with a NullPointerException because JAX-WS can't find the faultcode.
So I found the answer to my question. WebSphere 7 uses Axis2. Axis2's MessageContext provides a property called "TRANSPORT_IN" which contains a ByteArrayInputStream. TRANSPORT_IN, as the name implies, contains the exact SOAP message received.
I parsed through the original SOAP message in my Handler#handleFault method using a SAXHandler to retrieve the abc:fault message. I then wrote the abc:fault > faultcode and faultstring to the soapenv:Fault faultcode and faultstring. My application then handles the SOAPFaultException as if it was a normal one.
I'm still very open to any better answers since this feels like roundabout way to do this.
Handler Code:
public boolean handleFault(SOAPMessageContext context) {
SOAPMessage m = context.getMessage();
if(m != null) {
SOAPBody body = m.getSOAPBody();
SOAPFault fault = body.getFault();
setAbcFault(fault, context);
}
}
private void setAbcFault(SOAPFault fault, MessageContext context) {
ByteArrayInputStream bis = (ByteArrayInputStream)context.get("TRANSPORT_IN");
// do sax parsing on the input stream
fault.setFaultCode(abcFaultCodeQName);
fault.setFaultString(abcFaultString);
}
If you are using JAX-WS, you can use SOAP faults. or that, you need an Exception with #WebFault annotation. You can find a good example in Using SOAP Faults and Exceptions in Java JAX-WS Web Services - Eben Hewitt on Java.
See the answer for returning null or throw exception and How to throw a custom fault on a JAX-WS web service?
Example:
#WebService
public class CalculatorWS {
public String factorial(int n) throws FactorialException {
if (n < 0) {
throw new FactorialException("Negative number!", // faultstring
"The number n = " + n); // detail
}
return BigIntegerMath.factorial(n).toString();
}
}
With:
public class FactorialException extends Exception {
String detail;
public FactorialException(String message, String detail) {
super(message);
this.detail = detail;
}
public String getFaultInfo() {
return detail;
}
}
If the request is:
<soapenv:Envelope ... >
<soapenv:Header/>
<soapenv:Body>
<test:factorial>
<arg0>-1</arg0>
</test:factorial>
</soapenv:Body>
</soapenv:Envelope>
The response is:
<soapenv:Envelope ... >
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Negative number!</faultstring>
<detail>
<ns2:FactorialExceptionBean xmlns:ns2="http://...">
The number n = -1
</ns2:FactorialExceptionBean>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
(Tested in Websphere 7)

Spring WS with jaxb null object in request

I have Spring WS to which i am sending request of Object Request.java class, if i hardcode value in jaxb class it is ok ( but this is not it..)
my soap request i test in SoapUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cas="http://jakisadres.com/caservice">
<soapenv:Header/>
<soapenv:Body>
<cas:Request>
<cas:atr1>some value</cas:machineName>
</cas:Request>
</soapenv:Body>
</soapenv:Envelope>
and what i get is :
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns3:Response xmlns:ns3="http://jakisadres.com/caservice">
<responseValue>response: null</responseValue>
</ns3:CARevokeCertResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
my endpoint:
#PayloadRoot(localPart = "Request", namespace = "http://jakisadres.com/caservice")
#ResponsePayload
public Response revokeCert(#RequestPayload Request param) {
String request= param.getAtr1();
Resoponse response_ = new Response();
response.setResponseValue("response: "+request);
return response;
}
and my jaxb marshaller class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"atr1"
})
#XmlRootElement(name = "Request")
public class Request{
protected String atr1;
public String getAtr1() {
return atr1;
}
public void setAtr1(String value) {
this.atr1 = value;
}
}
any clue what am I missing?
Probably your atr1 element is in the default namespace and not in http://jakisadres.com/caservice namespace..your request should either be:
<cas:Request>
<atr1>some value</atr1>
</cas:Request>
OR you can explicitly specify the namespace for atr1 field

How do I access SOAP headers in a spring soap endpoint?

Here is my SOAP request:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:str="http://app.strategyblocks.com/ws/schema/strategyblocks">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="...">
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">secret</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<str:updateKpiRequest>
<str:company_id>1</str:company_id>
<str:kpi>
<str:external_id>1134511</str:external_id>
<str:title>title</str:title>
<str:description>description</str:description>
</str:kpi>
</str:updateKpiRequest>
</soapenv:Body>
</soapenv:Envelope>
Here is my Endpoint class:
#Endpoint
public class UpdateKpiEndpoint {
// The namespace of both request and response as declared in the XSD file
public static final String NAMESPACE_URI = "http://app.strategyblocks.com/ws/schema/strategyblocks";
// The local name of the expected request.
public static final String REQUEST_LOCAL_NAME = "updateKpiRequest";
#PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
#ResponsePayload
public UpdateKpiResponse processUpdateKpi(#RequestPayload UpdateKpiRequest updateKpiRequest) {
try {
} catch (Exception e) {
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("FAILURE");
response.setDescription("Problem with update kpi request");
return response;
}
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("SUCCESS");
response.setDescription("Kpi has been updated");
return response;
}
}
At the moment I am passing a UsernameToken for authentication in the soap request, that is all working well and I have no problems with it what so ever. What I want to be able to achieve is to retrieve that username from the header in the body of processUpdateKpi method in my endpoint class, so that I can use it to find existing data for that user, I have tried to find examples of it being done and so far I have been unsuccessful, is it possible to do it? I have thought about also passing the username in the SOAP body as well, but I want to avoid it.
someone in the spring forums had a clear explanation on how to read the header from the endpoint class:
http://forum.springsource.org/showthread.php?109560-Unable-to-read-SoapHeader-in-Endpoint-class

Categories

Resources