How to configure CXF to not worry about unknown elements? - java

My service is consuming a soap service. The target service could add new fields which shouldnt break our service as long as we receive all the fields we need.
I am using CXF to generate java code from WSDL and it breaks whenever it finds a new field. Is it possible to configure CXF to ignore new fields?
The error is something like
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"http://www.a.com/sed/b/products/2014/03/types", local:"BidOnly"). Expected elements are <{http://www.a.com/sed/b/products/2014/03/types}SaleTeam>,
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:905) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:711) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:172) ~[cxf-rt-databinding-jaxb-3.2.0.jar:3.2.0]

I tried to solve the same problem and stumbled upon this question:
CXF - webservice endpoint has changed, WSDL has not
Apparently if you set "set-jaxb-validation-event-handler" to "false" it disables this validation for the unmarshaler. So in my code I added this:
import org.apache.cxf.jaxws.EndpointImpl;
...
EndpointImpl endpoint = new EndpointImpl(...);
endpoint.getProperties().put("set-jaxb-validation-event-handler", "false");
I know I'm answering an old question, but perhaps it will be useful to someone.

Related

schema validation for soap service in camel

Have hosted soap service using camel-cxf component with default POJO data format. Want to do schema validation and instead fault need to return custom soap message.
There are many places and many techniques to do that. It depends on your requirements and design solution.
You can do it by custom code in one of inbound CXF interceptors before request reaches first processor after Camel from endpoint.
You can do it by using Camel Validate component (maybe start looking from here: Apache Camel: Validation Component
Some time ago, after playing with different approaches I ended up with custom Processor to do validation (due to my requirements - must be inside Route, must provide all errors/warnings at once(not first only), must create custom error response with details about all errors, get better as possible performance and so on...
I used standard javax.xml.validation package.
That option is not too hard, but more coding required.
Code must create instance of javax.xml.validation.Schema out of XSD file.
It is thread safe and it can be cached.
Then out of it javax.xml.validation.Validator can be created and used.
It is not thread safe, so new one must be created every time. (It is not costly operation anyway).
Then to collect all errors and warnings at once instead of getting validation exception from first error/warrning custom Error Handler implementing org.xml.sax.ErrorHandler interface need to be provided to validator in that case. There you can collect all exception and warnings from validation and deal with them after full validation completed.
With CXF POJO format - body in Camel Message actually is not a SOAP Message body, but it
is org.apache.cxf.message.MessageContentsList; where SOAP Message body POJO is element 0, and if message has more parts they are there too.
To use javax.xml.validation.Validator Body POJO must be marshalled to javax.xml.transform.Source
MyPojoClass bodyObject = ((MessageContentsList) exchange.getIn().getBody()).get(0);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema requestedSchema = schemaFactory.newSchema(schemaUrl);
Validator validator = requestedSchema.newValidator();
// custom handler to collect all errors and warnings
SchemaValidationErrorHandler errHandler = new SchemaValidationErrorHandler();
validator.setErrorHandler(errHandler);
//Custom method convertPojo - uses JAXB Marshaller in standard way
Source xmlSource = convertPojo(bodyObject);
validator.validate(xmlSource);
After all if Error Handler collects warnings and errors and does not throw Exception right away, all errors/warnings will be in it and can be handled as needed.
P.S. Performance is better when Schema object created ones and cached somewhere. Schema object creation is costly operation.

CXf- unexpected element (uri:"", local:"ns2.CustomerData"). Expected elements are <{customerbean}CustomerData>

I am Using CXF for Developing a rest base web service.and in Get method application type is JSON. Using WADL I have generated code.
Issue 1 - In Data class #XmlRootElement is missing.
Now After adding it manually when I consume the service using generated client I got exception
unexpected element (uri:"", local:"ns2.CustomerData"). Expected elements are <{customerbean}CustomerData>
I have gone through various post and if I remove namespace from my Data class as well as client data class then it works fine. But if namespace is removed than wadl2java doesn't work well.
I guess due to some thin server is not responding with proper namespace in response in case of JSON as the same will work if I change data type to XML
I have removed namespace from #XmlRootElement and added the same into #XmlType, and it started working for me.

Override CXF error handling

I am working on some web-services based application and I have a question about Apache CXF unmarshalling. In our project we use CXF 2.4.1 version.
When some SOAP request is incorrect (e.g. some field is text instead of numeric) CXF throws standard SOAPFaultException and SOAP response is built up with standard fields like:
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Unmarshalling Error: some field missing</faultstring>
</soap:Fault>
Project requirements says that in case of any fault system need to respond in other format, like:
<soap:body>
<ResponseState>
<ErrorCode>2732</ErrorCode>
<ErrorMessage>Unmarshalling Error: some field missing</ErrorMessage>
<ErrorDetails> some details </ErrorDetails>
<some other fields>
...
</ResponseState>
</soap:body>
So the question is: how can I override somehow this error handling and respond in my format, not default?
Thanks in advance.
P.S. I tried to look into some ValidationEventHandler principals, but it works in some other way in CXF 2.0 and higher.
OK, So after lot of research I've found some ways of CXF error handling.
*. ValidationEventHandler gives you possibility to throw your own exception instead of standard one. BUT you can't change responding behavior and you can't change SOAP response format.
*. Another way to alter error handling is to create your own interceptor. CXF workflow is built on chain of interceptors. There's 4 type of interceptors: inInterceptor, outInterceptor, inFaultInterceptor and outFaultInterceptor.
Using some smart hacks you can change workflow through creating your own interceptor (with adding it to chain), and remove standard interceptor from chain (if you know it's class name). So you can actually do anything you need.
BUT as far as all these interceptors marshall response manually (xmlWriter.writeStartElement() etc) it could be a great challenge to write your own interceptors for each flow phase. It could be real huge bunch of work.
Unfortunately, I haven't found good reference about CXF interceptors.
Another thing - if you need to return regular response instead of SOAPFaultException you may need additional information like: actual service that return this response, service parameters passed in request etc. I haven't found this info in accessible parameters in interceptors. And, surely, by doing so you cheat client code that will return OK instead of real exception.
*. Designing your wsdl's with all params as text may be very not very good solution:
a. Consumer of your services may be really confused if no data types and validation rules in wsdl.
b. You'll need to 'reinvent the wheel' for validation. I mean that you'll need to code your own validator that could be very difficult with some complicated rules. At the same time XSD has all of this validations implemented and good tested.
And finally about my situation: we discussed it with requirement manager and decided to allow CXF throw it's own standard exceptions if XML schema requirements violated in request. It's good solution because now we are using all the power of XSD validation and don't waste our time on complicated and useless work.
Great thanks to #ericacm for answer.
You can certainly generate a better error response than the default using ValidationEventHandler and throwing a Fault that conforms to the JAX-WS Fault spec. But it will only allow you so much customization - there will be some elements that you have no control over. For example, here is the ValidationEventHandler response from one of my apps:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Errors in request</faultstring>
<detail>
<ns2:ValidationFault xmlns:ns2="http://notification.ws.foo.com/">
<errors>
<error>
<inputElement>topicId</inputElement>
<errorMessage>java.lang.NumberFormatException: For input string: "" [line:6]</errorMessage>
</error>
</errors>
</ns2:ValidationFault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
You can't do anything about the <soap:Fault>, <faultcode> and <faultstring> elements. But everything from <ValidationFault> to </ValidationFault> is custom.
If you need to have more detailed control over the response then you should change the field type from numeric to string and then do the validation in your code instead of letting the unmarshaller catch the error.
Yes, I agree, forcing it to be a string would suck but if the response has to be exactly what you spec'd above it will not be possible without diving deeper into CXF than the JAX-WS layer (for example using an interceptor).
Another option is to use the CXF Transform feature
<entry key="Fault" value="ResponseState=..."/>
This will map the original fault from the server into any other fault so that it can be accepted by your client.

How do I return a (custom) SOAPFault from an Axis web service?

I have some WSDL from which I need to generate a web service implementation. I'm using Eclipse, and Axis1.4, and running on Weblogic9.2.
Generating the server stubs goes fine, and I've implemented the code I need to. However, for compatibility with the exising implementation we are emulating, I need to return SOAP faults for some specified error conditions.
That is, I need the SOAP body of the response to look like this example:
<soapenv:Body>
<soapenv:Fault>
<faultcode xmlns:ns1="foobar">ns1:1234</faultcode>
<faultstring>The supplied parameter name ABCD is not recognised.</faultstring>
<detail>
<FaultDetail>An error processing the web service [MyService]: Unknown parameter:ABCD</FaultDetail>
<ns2:hostname xmlns:ns2="http://xml.apache.org/axis/">planet</ns2:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
From (much) googling, I think I should be able to do this by throwing a SOAPFaultException. But the message stub throws only java.rmi.RemoteException, so I've tried passing the SOAPFaultException to the RemoteException. That gives me something like this:
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>java.rmi.RemoteException: My remote exception; nested exception is:
javax.xml.rpc.soap.SOAPFaultException: soap fault string</faultstring>
<detail>
<ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">myhostname</ns1:hostname>
</detail>
</soapenv:Fault>
</soapenv:Body>
... in other words, it hasn't resulted in a SOAP fault.
I've tried a lot of other stuff, and I'm pretty much stuck. So can someone tell me (ideally with an example) how to return a SOAP fault response with content I can specify, in my environment?
I'm not wedded to using Axis (but I've more experience with that than anything else). If you suggest an alternative, please note I need in the web service method to invoke another (authenticated) web service, and I've only been able to get that to work in Axis1.4...
Your second code post is a SOAP fault (note the soapenv:Fault inside the soapenv:Body).
Basically all of the frameworks's default behavior is to return the standard SOAP fault and provide you the ability to enter your own information in the fault code, fault string, and fault detail fields.
See the docs on the Axis 1 exception: http://ws.apache.org/axis/java/apiDocs/org/apache/axis/AxisFault.html
It has constructors for setting the qname of various fields, so you should be able to reference your own items there.
Many people will use the fault detail field and serialize their own XML type inside it using DOM.
Last but not least Axis1's prime time was circa 2000-2004, you will find it difficult to get answers and support around it. Most people have moved from Axis1 to Apache CXF, Axis2, or just straight up
JAX-WS (now included in JDK6+). There is also the Spring Web Services project, which provides full customization of all of the behaviors in the stack (marshalling, which bean gets executed, etc).
Just all of these frameworks use WSS4J for their web service security, and can support the standard username token, x509 token, etc. Nevertheless, once you get the basic messages being passed back and forth, you'll likely have to work through the details of WS-Security.

cxf.jaxrs: IllegalArgumentException when using JAXRSServerFactoryBean

I ran into the following issue when setting up a JAXRS test service in a unit test.
This is the code (taken from an AbstractJUnit4SpringContextTests-derived test class):
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setServiceBeans(applicationContext.getBean("searchXY"));
sf.setAddress("http://localhost:9000/");
sf.create();
restClient = new RestTestClient();//custom class for client-side testing
....
InputStream dummyRequestFileAsStream = getInputStreamForClasspathResource(
DUMMY_REQUEST_FILE);
LOGGER.info("Testing searchQuery ReST service access");
int httpStatus = restClient.postXmlStream(
"http://localhost:9000/search/searchXY",
dummyRequestFileAsStream);
I'm feeding an XML test file into the service. CXF would impertinently try to wrap the xml into a javax.xml.bind.JAXBElement, invoke the service, and fail with an IllegalArgumentException (in the reflection API) because the service of course does not accept a JAX-RS-specific element but rather the SearchRequest element that I defined in my XSD before.
However, when I insert the following line into my spring context, everything's fine:
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
Anyone else seen this?
It's difficult to see why the original issue is happening without more details being provided. The above import is always required and I've never tried testing without it being in the spring context. What is the exception trace ? Perhaps the JAXRS interceptors are not even involved without the import ?
cheers, Sergey
It turns out I was wrong: The problem was actually with the XSD: I had an XSD element "searchRequest" that is of type "SearchRequest" (sic, capital S), and additionally another root element that is using an extended type, derived from SearchRequest. It seems that cxf is having problems with a type that is used both as a root element's type and as a type for XSD inheritance. After creating an additional type AbstractSearchRequest and having all types inherit from that type the problem went away.

Categories

Resources