There is a bunch of legacy JAX-WS request code that had to be extended and include now a field holding "<!CDATA[[...]]>" encapsulated data.
We managed to get the field into the request, but it gets sent to the server with the CDATA being XML-encoded:
<data><![CDATA[<?xml version=....
<CheckData>
...
</CheckData>
]]></data>
There are questions and instructions available (eg. JAXB Marshalling Unmarshalling with CDATA and https://coderleaf.wordpress.com/2016/11/14/handling-cdata-with-jaxb/) but those all deal with the Marshaller either being directly available or being embedded into a proper application-server environment.
We have created a CdataCharacterEscapeHandler that would perform the (not-)encoding of CDATA fields properly and this also works when we use it in a manually created Marshaller.
Unfortunately our client is built around a JaxWsProxyFactoryBean proxy code that hides all the magic inside and did not change it's behavior no matter what we tried. (These classes are generated from an XSD that is processed with the Apache cxf-codegen-plugin through Maven.)
...
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
LogHandler.configureFactory(factory);
factory.setServiceClass(PaymentCheck.class);
factory.setAddress(serviceUrl);
factory.setUsername(username);
factory.setPassword(password);
Check checkProxy = (Check)factory.create();
CheckResult = checkProxy.check(paramA, paramB);
...
The JaxWsProxyFactoryBean hides all the creation logic of the Marshaller, Bindings etc. inside which we have not found a way to change/influence from the outside, so it seems the default CharacterEscapeHandler is used that does not know about CDATA and encodes all values XML-style.
We could not find any documentation, instruction or example how to use or inject the custom CharacterEscapeHandler into the
Is it possible to configure/change the JaxWsProxyFactoryBean setup/creation so that it also uses the CDATA-aware CharacterEscapeHandler?
While we still could not find any documentation or example online through lots of debugging and reverse-engineering we managed to find a solution.
It is possible to provide custom marshaller properties into the JaxWsProxyFactoryBean that are used during creation of the internal Marshaller instance.
Those properties can be provided as part of a JAXBDataBinding to the factory.
A created instance of the custom CharacterEscapeHandler has to be put into the marshaller property "com.sun.xml.bind.characterEscapeHandler"
(or "com.sun.xml.bind.marshaller.CharacterEscapeHandler"
is also valid) of the JAXBDataBinding and then these will be respected by the factory.
...
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
LogHandler.configureFactory(factory);
factory.setServiceClass(PaymentCheck.class);
factory.setAddress(serviceUrl);
factory.setUsername(username);
factory.setPassword(password);
JAXBDataBinding jaxbDataBinding = new JAXBDataBinding();
Map<String, Object> marshallerProperties = new HashMap<>();
marshallerProperties.put("com.sun.xml.bind.characterEscapeHandler", new CdataCharacterEscapeHandler());
jaxbDataBinding.setMarshallerProperties(marshallerProperties);
factory.setDataBinding(jaxbDataBinding);
Check checkProxy = (Check)factory.create();
CheckResult = checkProxy.check(paramA, paramB);
...
Using this solution the JAX-WS proxy client created by the JaxWsProxyFactoryBean finally sends over the proper request to the server.
<data><![CDATA[<?xml version=....
<CheckData>
...
</CheckData>
]]></data>