Avoid soap fault response (org.apache.cxf)

30 Views Asked by At

I am creating a SOAP service using org.apache.cxf. Everything is functioning properly: data entry, processing with business logic, and returning data are all correct. However, issues arise when the entered data does not comply with the contract. For example, if a numerical field is submitted as a letter, it bypasses the validator and triggers a SOAP fault. Instead of returning a SOAP fault, I aim to return a custom object that indicates the errors. Is this achievable with this technology? I am attaching the code I am currently using. (I have attempted to extend two different classes: AbstractSoapInterceptor and AbstractPhaseInterceptor<SoapMessage>).

SoapFaultInterceptor:

package es.app.soap.interceptores;

import java.util.ArrayList;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;

public class SoapFaultInterceptor extends AbstractSoapInterceptor {
    
    public SoapFaultInterceptor() {
        super(Phase.PRE_STREAM); //UNMARSHAL
        //addBefore(ClientFaultConverter.class.getName());
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        // TODO Auto-generated method stub
        System.out.println("SoapFaultInterceptor handleMessage ");        
        System.out.println("SoapFaultInterceptor handleMessage END ");
    }
    
    
    @Override
    public void handleFault(SoapMessage message) {
        // TODO Auto-generated method stub
        System.out.println("SoapFaultInterceptor handleFault ");
        //message.setContent(Exception.class, null);
        

        CustomSoapFaultResponse respError = new CustomSoapFaultResponse();
        CustomSoapFaultResponseError error = new CustomSoapFaultResponseError();
        error.setCodigo("test code");
        error.setDescripcion("test description");
        CustomSoapFaultResponseErrores errores = new CustomSoapFaultResponseErrores();
        errores.getError().add(error);
        respError.setErrores(errores);
        
        // Elimina el SoapFault del mensaje saliente
        message.setContent(CustomSoapFaultResponse.class, respError);

        System.out.println("SoapFaultInterceptor handleFault END ");
    }

}

CustomAbstractPhaseInterceptor:

package es.app.soap.interceptores;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.binding.soap.interceptor.Soap11FaultOutInterceptor;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.springframework.stereotype.Component;


public class CustomAbstractPhaseInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
    
    public CustomAbstractPhaseInterceptor() {
        //super(Phase.SETUP);
        super(Phase.PRE_STREAM);
        //this.getBefore().add(Soap11FaultOutInterceptor.class.getName());
        System.out.println("CustomAbstractPhaseInterceptor Constructor");
    }
    
    
    
    
    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        // TODO Auto-generated method stub
        System.out.println("CustomAbstractPhaseInterceptor handleMessage");
        
        
    }
    
    
    @Override
    public void handleFault(SoapMessage message) {
        System.out.println("CustomAbstractPhaseInterceptor handleFault");
        
        //message.setContent(Exception.class, null);

        try {
            
            String customSoapResponse = "<Errores><Error>test error</Error></Errores>";
            SOAPMessage soapMessage;
            try {
                soapMessage = createSoapMessage(customSoapResponse);
                
                message.setContent(SOAPMessage.class, soapMessage);
                //message.getExchange().setOutMessage(message);
            } catch (TransformerException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            
        } catch (SOAPException | IOException e) {
            throw new Fault(e);
        }
        
        //message.getInterceptorChain().pause();
    }

    
    
    private SOAPMessage createSoapMessage(String xml) throws SOAPException, IOException, TransformerException {
        InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
        StreamSource streamSource = new StreamSource(inputStream);
        DOMResult domResult = new DOMResult();
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.transform(streamSource, domResult);

        // Create a SOAPMessage from the transformed DOMResult
        SOAPMessage soapMessage = javax.xml.soap.MessageFactory.newInstance().createMessage();
        SOAPBody soapBody = soapMessage.getSOAPBody();
        soapBody.addDocument((org.w3c.dom.Document) domResult.getNode());

        return soapMessage;
    }

}

I have tried multiple ways that I have searched through Googling but none of them worked.

Is it possible to avoid soap fault? Whatever you do, the answer is always the same, I have attached it below:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>Unmarshalling Error: cvc-length-valid: Value 'a' with length = '1' is not facet-valid with respect to length '9' for type 'NameType'.</faultstring>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

I hope something like this:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:ErrorResponse>
         <Error>Unmarshalling Error: cvc-length-valid: Value 'a' with length = '1' is not facet-valid with respect to length '9' for type 'NameType'.</Error>
      </soap:ErrorResponse>
   </soap:Body>
</soap:Envelope>

I have tried creating a soap message from scratch, I am not able to. I have tried deleting the Fault, and creating a custom message, but it didnt work either.

0

There are 0 best solutions below