I call a web-service which can periodically add some element in their contract.
Example: the SOAP response body contains:
<picture>
<active>true</active>
<code>172</code>
<label>Nikon D3200 Black</label>
<downloadEnabled>true</downloadEnabled>
</picture>
<picture>
<active>false</active>
<code>177</code>
<label>Nikon D5200 Red</label>
<downloadEnabled>true</downloadEnabled>
<extraField>none</extraField>
</picture>
and my CXF generated JAXB Bean looks like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "pictureListJAXB", propOrder = {
"active",
"code",
"label",
"downloadEnabled",
"extraField"
})
public class PictureListJAXB {
protected boolean active;
protected String code;
protected String label;
protected boolean downloadEnabled;
@XmlElement(nillable = true)
protected String extraField
// And Getters / Setters comes here after
}
The JAXB beans are generated with the maven plugin cxf-codegen-plugin
version 2.6.2 (from apache.cxf).
Now I want to know if there is a solution to make my Bean to be fault tolerant in case a new element appears in the SOAP response:
<picture>
<active>true</active>
<code>172</code>
<label>Nikon D3200 Black</label>
<downloadEnabled>true</downloadEnabled>
<newUnmappedElement>anything irrelevant</newUnmappedElement>
</picture>
For now, when I recieve such response, I got an Unmarshalling Error
because this new element.
My JAXB contains the minimal fields I want to manage but I want the bean to be able to cope with new element and just ignore them.
Is there any way to do it without regenerating the JAXB Bean? (As now I have to regenerate the Beans and release my project)
I checked the CXF options (and xjc) and found nothing in the doc (and google). The unmarshalling operation is automatically done in the ReferentialService
also generated by CXF, then an option to modify the generation of this part would be sufficient.
Here is the code to call the web-service using the CXF generated classes:
public ReferentialService getReferentialService(String resource, String auth) throws RuntimeException {
// These two classes are generated by CXF
Referential referential;
ReferentialService referentialService;
// Get the resource URL in form http://myserver:port/remote-backend/resource?wsdl
referential = new Referential(new URL(MyConfigUtil.getWSDL(resource)));
referentialService = referential.getReferentialServicePort();
BindingProvider bp = (BindingProvider) referentialService;
// Get the endpoint URL in form http://myserver:port/remote-backend/resource
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, MyConfigUtil.getWebServiceEndPoint(resource));
// Add SOAP credentials
String username = HttpBasicAuthHelper.getUsername(auth);
String password = HttpBasicAuthHelper.getPassword(auth);
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
return referentialService;
}
and the call:
// Throws Exception just for the sample code
public InputStream listPictures(QueryDTO request, String resource, String auth) throws Exception {
InputStream is = null;
if (request != null) {
// This is the WS Call which failed with unmarshal error
List<PictureListJAXB> result = getReferentialService(resource, auth).getPictures(request);
// Some code to convert JAXB into a XML stream
is = convertObjectToXmlStream(result);
}
return is;
}
UPDATE:
I saw this post and my feeling was the same: JAXB will just ignore the unmapped elements if used alone without CXF. By using the cxf-codegen-plugin
, it is not the case.
I finally found the answer by looking to this another post but as I do not use the declarative way like in the post, it makes me guessed I should be able to add some properties on the binding provider.
My modification to my code is to add these properties in the
BindingProvider
like this in thegetReferentialService
method:and for the test, I just created an inner class
ValidatorHandler
:By doing this, I do not need to modify my generated beans (JAX-B) and use them as they were generated by default.