Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse engineering: How to generate SOAP Request XML in the backend?

I have the following classes:

WS Interface:

package com.mypackage;

import javax.ejb.Remote;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

@Remote
@SOAPBinding(style = Style.DOCUMENT)
@WebService(name = "MathService", targetNamespace = "http://mypackage.com/")
public interface MathServiceWS {

    @WebResult(name = "result", targetNamespace = "http://mypackage.com/")
    @RequestWrapper(localName = "addRequest", className = "AddRequest", targetNamespace = "http://mypackage.com/")
    @WebMethod(action = "http://mypackage.com/add", operationName = "add")
    @ResponseWrapper(localName = "addResponse", className = "AddResponse", targetNamespace = "http://mypackage.com/")
    Long add(@WebParam(name = "add", targetNamespace = "http://mypackage.com/") AddBean add);
}

WS Implementation:

package com.mypackage;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless(mappedName = "MathService")
@WebService(serviceName = "MathService", endpointInterface = "com.mypackage.MathServiceWS", portName = "MathServicePort", targetNamespace = "http://mypackage.com/")
public class MathService implements MathServiceWS {

    @Override
    public Long add(AddBean add) {
        Long first = new Long(add.getFirst().intValue());
        Long second = new Long(add.getSecond().intValue());
        return Long.valueOf(Math.addExact(first.longValue(), second.longValue()));
    }
}

The bean:

package com.mypackage;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
    name = "Add",
    namespace = "http://mypackage.com/",
    propOrder = {
        "first",
        "second"
    }
)
public class AddBean implements Serializable {

    private static final long serialVersionUID = -7727938355039425419L;

    @XmlElement(required = true)
    private Integer first;

    @XmlElement(required = true)
    private Integer second;

    public AddBean() {

    }

    public Integer getFirst() {
        return first;
    }

    public void setFirst(Integer first) {
        this.first = first;
    }

    public Integer getSecond() {
        return second;
    }

    public void setSecond(Integer second) {
        this.second = second;
    }
}

After deploying this WS, when I'm adding the WSDL in SoapUI, the add method request is as follows after giving the user input:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myp="http://mypackage.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <myp:addRequest>
         <myp:add>
            <first>1</first>
            <second>2</second>
         </myp:add>
      </myp:addRequest>
   </soapenv:Body>
</soapenv:Envelope>

Now I want to have the above SOAP request XML in my com.mypackage.MathService.add(AddBean) method with the given user input.

  • Using JAXB on com.mypackage.AddBean only generates partial request
  • The WebService Handlers is not useful to fulfill my requirement

Any pointer would be very helpful.

like image 505
Tapas Bose Avatar asked May 18 '26 01:05

Tapas Bose


1 Answers

You may create an custom SOAPHandler object and can read the request payload and set it to SOAPMessageContext via custom property. Make sure you set the scope as application.

In your service class, inject the javax.xml.ws.WebServiceContext using @javax.annotation.Resource and access payload set via your custom property.

For example:
1. Create Handler and register it.

public class PopulateSOAPMessagePayloadHandler implements SOAPHandler<SOAPMessageContext> {
    public static final String SOAP_MESSAGE_PAYLOAD = "__soap_message_payload";

    @Override
    public boolean handleMessage(SOAPMessageContext smc) {
        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!outboundProperty.booleanValue()) {
            // for incoming:
            ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
            try {
                smc.getMessage().writeTo(bout);
                String payload = bout.toString(StandardCharsets.UTF_8.name());

                smc.put(SOAP_MESSAGE_PAYLOAD, payload);  //Set payload
                smc.setScope(SOAP_MESSAGE_PAYLOAD, MessageContext.Scope.APPLICATION);  //make it application scope

            } catch (SOAPException | IOException e) {
                e.printStackTrace();
                // handle exception if needed
                throw new WebServiceException(e);
            }

        }
        return true;
    }
 // Other method (no-op) omitted 
}


2. Get the payload

public class MathService implements MathServiceWS {
    @Resource
    private WebServiceContext context;

    @Override
    public Long add(AddBean add) {
        String payload = (String) context.getMessageContext().get(SOAP_MESSAGE_PAYLOAD);

        Long first = new Long(add.getFirst().intValue());
        Long second = new Long(add.getSecond().intValue());
        return Long.valueOf(Math.addExact(first.longValue(), second.longValue()));
    }
}

Hope it helps.

like image 116
skadya Avatar answered May 19 '26 15:05

skadya



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!