[ 
https://issues.apache.org/jira/browse/CXF-7669?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Mark Czubin updated CXF-7669:
-----------------------------
    Description: 
When our response text contains escape characters then those will be encoded 
twice. 

For example when I return "hello > world". Cxf will encode this as "hello &> 
world"
{code:java}
hello &> world{code}
 

Below a test with all the interceptors used in our setup on production: 
{code:java}
package be.vlaanderen.omgeving.rest.controller.parameter.v1;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.binding.Binding;
import org.apache.cxf.binding.BindingFactory;
import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.endpoint.EndpointException;
import org.apache.cxf.endpoint.EndpointImpl;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.staxutils.StaxUtils;
import org.apache.cxf.wsdl.interceptors.BareOutInterceptor;
import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor;
import org.apache.cxf.wsdl11.WSDLServiceFactory;
import org.junit.Test;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.TreeSet;

import static java.util.Collections.emptyList;
import static 
org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.OUT_BUFFERING;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

public class CxfIsUnstable {
    CxfFacade cxf = new CxfFacade();

    @Test
    public void 
givenAResponseWithAmpersans_whenMarshallingToXml_theAmpersandAreEncoded_onlyOnce()
 throws Exception {
        cxf.setupExampleService();

        String request = cxf.demarshallRequest("<request>hello &amp; 
world</request>");
        assertThat(request).isEqualTo("hello & world");

        String responseXml = cxf.marshallResponse("hello & world");
        assertThat(responseXml).isEqualTo("<response>hello &amp; 
world<</response>");
    }

    static class CxfFacade {
        private final SAAJOutInterceptor saajOutInterceptor = new 
SAAJOutInterceptor();
        private final BareOutInterceptor outInterceptor = new 
BareOutInterceptor();
        private final DocLiteralInInterceptor inInterceptor = new 
DocLiteralInInterceptor();
        private SoapMessage message;

        private List<Object> messageContents;

        public String demarshallRequest(String input) throws XMLStreamException 
{
            message.setContent(XMLStreamReader.class, 
XMLInputFactory.newInstance().createXMLStreamReader(new 
ByteArrayInputStream(input.getBytes())));
            
StaxUtils.skipToStartOfElement(message.getContent(XMLStreamReader.class));

            inInterceptor.handleMessage(message);

            assertThat(message.getContent(Exception.class)).isNull();
            messageContents = message.getContent(List.class);
            String requestContent = (String) messageContents.get(0);

            saajOutInterceptor.handleMessage(message);
            return requestContent;
        }

        public String marshallResponse(String responseBody) throws Exception {
            messageContents.set(0, responseBody);

            ByteArrayOutputStream boas = new ByteArrayOutputStream();
            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
            XMLStreamWriter output = 
xmlOutputFactory.createXMLStreamWriter(boas);
            message.setContent(XMLStreamWriter.class, output);
            message.put(OUT_BUFFERING, "true");
            outInterceptor.handleMessage(message);
            output.flush();
            boas.flush();

            return boas.toString();
        }

        public void setupExampleService() throws JAXBException, 
EndpointException {
            Bus bus = BusFactory.newInstance().createBus();
            BindingFactoryManager bfm = 
bus.getExtension(BindingFactoryManager.class);
            BindingFactory bf = mock(BindingFactory.class);
            Binding binding = mock(Binding.class);

            given(bf.createBinding(null)).willReturn(binding);
            given(binding.getInFaultInterceptors()).willReturn(emptyList());
            given(binding.getOutFaultInterceptors()).willReturn(emptyList());

            bfm.registerBindingFactory("http://schemas.xmlsoap.org/wsdl/soap/";, 
bf);
            String ns = "http://webservice.example-V1.vlaanderen.be";;

            WSDLServiceFactory factory = new WSDLServiceFactory(bus, 
"classpath:/files/ExampleService.wsdl");

            Service service = factory.create();
            service.setDataBinding(new 
JAXBDataBinding(JAXBContext.newInstance()));

            EndpointInfo endpointInfo = service.getEndpointInfo(new QName(ns, 
"exampleServicePort"));
            EndpointImpl endpoint = new EndpointImpl(bus, service, 
endpointInfo);

            BindingOperationInfo operation = 
endpointInfo.getBinding().getOperation(new QName(ns, "example"));
            
operation.getOperationInfo().getInput().getMessagePartByIndex(0).setTypeClass(String.class);

            message = new SoapMessage(new MessageImpl());
            Exchange exchange = new ExchangeImpl();
            message.setExchange(exchange);
            message.setInterceptorChain(new PhaseInterceptorChain(new 
TreeSet<>()));

            exchange.put(Service.class, service);
            exchange.put(Endpoint.class, endpoint);
            exchange.put(Binding.class, endpoint.getBinding());
        }
    }
}
{code}

  was:
When our response text contains escape characters then those will be encoded 
twice. 

For example when I return "hello > world". Cxf will encode this as "hello 
&amp;&gt; world".

Below a test with all the interceptors used in our setup on production: 
{code:java}
package be.vlaanderen.omgeving.rest.controller.parameter.v1;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.binding.Binding;
import org.apache.cxf.binding.BindingFactory;
import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.endpoint.EndpointException;
import org.apache.cxf.endpoint.EndpointImpl;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.staxutils.StaxUtils;
import org.apache.cxf.wsdl.interceptors.BareOutInterceptor;
import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor;
import org.apache.cxf.wsdl11.WSDLServiceFactory;
import org.junit.Test;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.TreeSet;

import static java.util.Collections.emptyList;
import static 
org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.OUT_BUFFERING;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

public class CxfIsUnstable {
    CxfFacade cxf = new CxfFacade();

    @Test
    public void 
givenAResponseWithAmpersans_whenMarshallingToXml_theAmpersandAreEncoded_onlyOnce()
 throws Exception {
        cxf.setupExampleService();

        String request = cxf.demarshallRequest("<request>hello &amp; 
world</request>");
        assertThat(request).isEqualTo("hello & world");

        String responseXml = cxf.marshallResponse("hello & world");
        assertThat(responseXml).isEqualTo("<response>hello &amp; 
world<</response>");
    }

    static class CxfFacade {
        private final SAAJOutInterceptor saajOutInterceptor = new 
SAAJOutInterceptor();
        private final BareOutInterceptor outInterceptor = new 
BareOutInterceptor();
        private final DocLiteralInInterceptor inInterceptor = new 
DocLiteralInInterceptor();
        private SoapMessage message;

        private List<Object> messageContents;

        public String demarshallRequest(String input) throws XMLStreamException 
{
            message.setContent(XMLStreamReader.class, 
XMLInputFactory.newInstance().createXMLStreamReader(new 
ByteArrayInputStream(input.getBytes())));
            
StaxUtils.skipToStartOfElement(message.getContent(XMLStreamReader.class));

            inInterceptor.handleMessage(message);

            assertThat(message.getContent(Exception.class)).isNull();
            messageContents = message.getContent(List.class);
            String requestContent = (String) messageContents.get(0);

            saajOutInterceptor.handleMessage(message);
            return requestContent;
        }

        public String marshallResponse(String responseBody) throws Exception {
            messageContents.set(0, responseBody);

            ByteArrayOutputStream boas = new ByteArrayOutputStream();
            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
            XMLStreamWriter output = 
xmlOutputFactory.createXMLStreamWriter(boas);
            message.setContent(XMLStreamWriter.class, output);
            message.put(OUT_BUFFERING, "true");
            outInterceptor.handleMessage(message);
            output.flush();
            boas.flush();

            return boas.toString();
        }

        public void setupExampleService() throws JAXBException, 
EndpointException {
            Bus bus = BusFactory.newInstance().createBus();
            BindingFactoryManager bfm = 
bus.getExtension(BindingFactoryManager.class);
            BindingFactory bf = mock(BindingFactory.class);
            Binding binding = mock(Binding.class);

            given(bf.createBinding(null)).willReturn(binding);
            given(binding.getInFaultInterceptors()).willReturn(emptyList());
            given(binding.getOutFaultInterceptors()).willReturn(emptyList());

            bfm.registerBindingFactory("http://schemas.xmlsoap.org/wsdl/soap/";, 
bf);
            String ns = "http://webservice.example-V1.vlaanderen.be";;

            WSDLServiceFactory factory = new WSDLServiceFactory(bus, 
"classpath:/files/ExampleService.wsdl");

            Service service = factory.create();
            service.setDataBinding(new 
JAXBDataBinding(JAXBContext.newInstance()));

            EndpointInfo endpointInfo = service.getEndpointInfo(new QName(ns, 
"exampleServicePort"));
            EndpointImpl endpoint = new EndpointImpl(bus, service, 
endpointInfo);

            BindingOperationInfo operation = 
endpointInfo.getBinding().getOperation(new QName(ns, "example"));
            
operation.getOperationInfo().getInput().getMessagePartByIndex(0).setTypeClass(String.class);

            message = new SoapMessage(new MessageImpl());
            Exchange exchange = new ExchangeImpl();
            message.setExchange(exchange);
            message.setInterceptorChain(new PhaseInterceptorChain(new 
TreeSet<>()));

            exchange.put(Service.class, service);
            exchange.put(Endpoint.class, endpoint);
            exchange.put(Binding.class, endpoint.getBinding());
        }
    }
}
{code}


> Cxf encodes escape caracters twice in JDK9.0.5 and JDK8_161
> -----------------------------------------------------------
>
>                 Key: CXF-7669
>                 URL: https://issues.apache.org/jira/browse/CXF-7669
>             Project: CXF
>          Issue Type: Bug
>    Affects Versions: 3.2.2
>            Reporter: Mark Czubin
>            Priority: Critical
>         Attachments: ExampleService.wsdl
>
>
> When our response text contains escape characters then those will be encoded 
> twice. 
> For example when I return "hello > world". Cxf will encode this as "hello &> 
> world"
> {code:java}
> hello &amp;&gt; world{code}
>  
> Below a test with all the interceptors used in our setup on production: 
> {code:java}
> package be.vlaanderen.omgeving.rest.controller.parameter.v1;
> import org.apache.cxf.Bus;
> import org.apache.cxf.BusFactory;
> import org.apache.cxf.binding.Binding;
> import org.apache.cxf.binding.BindingFactory;
> import org.apache.cxf.binding.BindingFactoryManager;
> import org.apache.cxf.binding.soap.SoapMessage;
> import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
> import org.apache.cxf.endpoint.Endpoint;
> import org.apache.cxf.endpoint.EndpointException;
> import org.apache.cxf.endpoint.EndpointImpl;
> import org.apache.cxf.jaxb.JAXBDataBinding;
> import org.apache.cxf.message.Exchange;
> import org.apache.cxf.message.ExchangeImpl;
> import org.apache.cxf.message.MessageImpl;
> import org.apache.cxf.phase.PhaseInterceptorChain;
> import org.apache.cxf.service.Service;
> import org.apache.cxf.service.model.BindingOperationInfo;
> import org.apache.cxf.service.model.EndpointInfo;
> import org.apache.cxf.staxutils.StaxUtils;
> import org.apache.cxf.wsdl.interceptors.BareOutInterceptor;
> import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor;
> import org.apache.cxf.wsdl11.WSDLServiceFactory;
> import org.junit.Test;
> import javax.xml.bind.JAXBContext;
> import javax.xml.bind.JAXBException;
> import javax.xml.namespace.QName;
> import javax.xml.stream.XMLInputFactory;
> import javax.xml.stream.XMLOutputFactory;
> import javax.xml.stream.XMLStreamException;
> import javax.xml.stream.XMLStreamReader;
> import javax.xml.stream.XMLStreamWriter;
> import java.io.ByteArrayInputStream;
> import java.io.ByteArrayOutputStream;
> import java.util.List;
> import java.util.TreeSet;
> import static java.util.Collections.emptyList;
> import static 
> org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.OUT_BUFFERING;
> import static org.assertj.core.api.Assertions.assertThat;
> import static org.mockito.BDDMockito.given;
> import static org.mockito.Mockito.mock;
> public class CxfIsUnstable {
>     CxfFacade cxf = new CxfFacade();
>     @Test
>     public void 
> givenAResponseWithAmpersans_whenMarshallingToXml_theAmpersandAreEncoded_onlyOnce()
>  throws Exception {
>         cxf.setupExampleService();
>         String request = cxf.demarshallRequest("<request>hello &amp; 
> world</request>");
>         assertThat(request).isEqualTo("hello & world");
>         String responseXml = cxf.marshallResponse("hello & world");
>         assertThat(responseXml).isEqualTo("<response>hello &amp; 
> world<</response>");
>     }
>     static class CxfFacade {
>         private final SAAJOutInterceptor saajOutInterceptor = new 
> SAAJOutInterceptor();
>         private final BareOutInterceptor outInterceptor = new 
> BareOutInterceptor();
>         private final DocLiteralInInterceptor inInterceptor = new 
> DocLiteralInInterceptor();
>         private SoapMessage message;
>         private List<Object> messageContents;
>         public String demarshallRequest(String input) throws 
> XMLStreamException {
>             message.setContent(XMLStreamReader.class, 
> XMLInputFactory.newInstance().createXMLStreamReader(new 
> ByteArrayInputStream(input.getBytes())));
>             
> StaxUtils.skipToStartOfElement(message.getContent(XMLStreamReader.class));
>             inInterceptor.handleMessage(message);
>             assertThat(message.getContent(Exception.class)).isNull();
>             messageContents = message.getContent(List.class);
>             String requestContent = (String) messageContents.get(0);
>             saajOutInterceptor.handleMessage(message);
>             return requestContent;
>         }
>         public String marshallResponse(String responseBody) throws Exception {
>             messageContents.set(0, responseBody);
>             ByteArrayOutputStream boas = new ByteArrayOutputStream();
>             XMLOutputFactory xmlOutputFactory = 
> XMLOutputFactory.newInstance();
>             XMLStreamWriter output = 
> xmlOutputFactory.createXMLStreamWriter(boas);
>             message.setContent(XMLStreamWriter.class, output);
>             message.put(OUT_BUFFERING, "true");
>             outInterceptor.handleMessage(message);
>             output.flush();
>             boas.flush();
>             return boas.toString();
>         }
>         public void setupExampleService() throws JAXBException, 
> EndpointException {
>             Bus bus = BusFactory.newInstance().createBus();
>             BindingFactoryManager bfm = 
> bus.getExtension(BindingFactoryManager.class);
>             BindingFactory bf = mock(BindingFactory.class);
>             Binding binding = mock(Binding.class);
>             given(bf.createBinding(null)).willReturn(binding);
>             given(binding.getInFaultInterceptors()).willReturn(emptyList());
>             given(binding.getOutFaultInterceptors()).willReturn(emptyList());
>             
> bfm.registerBindingFactory("http://schemas.xmlsoap.org/wsdl/soap/";, bf);
>             String ns = "http://webservice.example-V1.vlaanderen.be";;
>             WSDLServiceFactory factory = new WSDLServiceFactory(bus, 
> "classpath:/files/ExampleService.wsdl");
>             Service service = factory.create();
>             service.setDataBinding(new 
> JAXBDataBinding(JAXBContext.newInstance()));
>             EndpointInfo endpointInfo = service.getEndpointInfo(new QName(ns, 
> "exampleServicePort"));
>             EndpointImpl endpoint = new EndpointImpl(bus, service, 
> endpointInfo);
>             BindingOperationInfo operation = 
> endpointInfo.getBinding().getOperation(new QName(ns, "example"));
>             
> operation.getOperationInfo().getInput().getMessagePartByIndex(0).setTypeClass(String.class);
>             message = new SoapMessage(new MessageImpl());
>             Exchange exchange = new ExchangeImpl();
>             message.setExchange(exchange);
>             message.setInterceptorChain(new PhaseInterceptorChain(new 
> TreeSet<>()));
>             exchange.put(Service.class, service);
>             exchange.put(Endpoint.class, endpoint);
>             exchange.put(Binding.class, endpoint.getBinding());
>         }
>     }
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to