Modify response of web service with JAX-WS

2019-01-25 19:45发布

问题:

How can I modify the namespace of the response like this:

old response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:GetAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
         <etat>0</etat>
         <montant>500.0</montant>
      </ns2:GetAmountResponse>
   </soap:Body>
</soap:Envelope>

new response wanted :

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
         <etat>0</etat>
         <montant>500.0</montant>
      </GetAmountResponse>
   </soap:Body>
</soap:Envelope>

I want to remove the ns2 namespce prefix.

回答1:

In the first case, the GetAmountResponse is in namespace http://ws.dsi.otn.com/dab while etat and montant are in a default (empty) namespace.

In the new message you want, GetAmountResponse, etat and montant are all in namespace http://ws.dsi.otn.com/dab.

The namespaces can be controlled from the namespaces of your classes. Use the same namespace in all and you will have them in the same namespace, leave classes with defaults and they default to empty namespace.

For example, if you were to have something like this in your web service class:

@WebMethod
    public 
    @WebResult(name = "getAmountResponse", targetNamespace = "http://ws.dsi.otn.com/dab")
    AmountResponse getAmount(
            @WebParam(name = "getAmountRequest", targetNamespace = "http://ws.dsi.otn.com/dab") AmountRequest request) {

        AmountResponse response = new AmountResponse();
        response.setEtat(0);
        response.setMontant(500.0);

        return response;
    }

with a response class like this:

@XmlRootElement
public class AmountResponse {
    private int etat;
    private double montant;
    // getter and setters omitted
}

you will end up with the first type of soap message.

But if you change the response class to look like this instead:

@XmlRootElement(namespace = "http://ws.dsi.otn.com/dab")
@XmlAccessorType(XmlAccessType.NONE)
public class AmountResponse {

    @XmlElement(namespace = "http://ws.dsi.otn.com/dab")
    private int etat;

    @XmlElement(namespace = "http://ws.dsi.otn.com/dab")
    private double montant;

    // getters and setter omitted
}

you will bring all tags in the same namespace and you get something equivalent to the new type of message you want. I said equivalent because I don't think you will get exactly this:

<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
     <etat>0</etat>
     <montant>500.0</montant>
</GetAmountResponse>

It's more likely to get something like this instead:

<ns2:getAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
     <ns2:etat>0</ns2:etat>
     <ns2:montant>500.0</ns2:montant>
</ns2:getAmountResponse>

It's the same "XML meaning" for both messages although they don't look the same.

If you absolutely want it to look like that, I think you will have to go "low level" and use something like a SOAP handler to intercept the response and modify it. But be aware that it won't be a trivial task to change the message before it goes on the wire.



回答2:

logical handler are enough to transform to the message as expected :

package com.ouertani.slim;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.LogicalMessage;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;

/**
 *
 * @author ouertani
 */
public class MyLogicalHandler implements LogicalHandler<LogicalMessageContext> {

    @Override
    public boolean handleMessage(LogicalMessageContext messageContext) {
        /// extract state and amount
        int state = 0;
        double amount = 200.0;
        transform(messageContext, state, amount);
        return false;
    }

    public boolean handleFault(LogicalMessageContext messageContext) {
        return true;
    }

    public void close(MessageContext context) {
    }
    private void transform( LogicalMessageContext messageContext, int etat, double montant){
            LogicalMessage msg = messageContext.getMessage();

        String htom = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+
   "<soap:Body>"+
      "<GetAmountResponse xmlns=\"http://ws.dsi.otn.com/dab\">"+
         "<etat>"+etat+"</etat>"+
         "<montant>"+montant+"</montant>"+
      "</GetAmountResponse>"+
   "</soap:Body>"+
"</soap:Envelope>";
        InputStream is = new ByteArrayInputStream(htom.getBytes());
        Source ht = new StreamSource(is);
        msg.setPayload(ht);
    }
}