I've got an a client for JAX-WS webservice. The problem that i faced is the exception Unmarshalling Error: Maximum Number of Child Elements limit (50000) Exceeded when response is mapping to Java Objects. So i think about manually SAX parsing response. Is there any kind of hack/interceptor that allows me to use nice JAX-WS method binding with manually SAX parsing(through InputStream) the response?
Actually there's no need to do that, since you can just override the property
org.apache.cxf.stax.maxChildElements
to get rid of the exception. For more information, check it out the official documentation: http://cxf.apache.org/docs/security.html
Related
I have been exploring on how to consume the web services and I found a good articles on JAX-Rs and it is the way to consume Rest Webservices. my task is to hit the URL which returns the XML as response and should be converted into Object which I have achieved using following code.
client = ClientBuilder.newClient();
//example query params: ?q=Turku&cnt=10&mode=json&units=metric
target = client.target(
"http://api.openweathermap.org/data/2.5/weather")
.queryParam("appid", apikey)
.queryParam("units", "metric")
;
And here is the piece of code which will map my XML response to java object
Example exampleObject = target.request(MediaType.APPLICATION_XML).get(Example.class);
This works fine, but the issue is my lead is saying use JIBX since it's faster.
Question 1 : How does target.request converts the xml response (does it use jibx or jaxb etc ?? )
Question 2 : If I have use JIBX I need to download the response as stream and do the marshalling and unmarshalling which I found not a right way to consume webservices, I am I right??
Please do help on this.
1: JAX-RS uses MessageBodyReaders to convert the HTTP entity stream into an object. By default, all JAX-RS implementations are required to ship a MessageBodyReader (and Writer) that uses JAXB to serialize/deserialize to/from XML when the content type is application/xml.
2: If you want to use something other than JAXB to deserialize XML, you could write your own MessageBodyReader that consumes “application/xml”. That would override the built-in JAXB reader.
An example of how to do this is available here:
https://memorynotfound.com/jax-rs-messagebodyreader/
Hope this helps, Andy
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.
I have one webservice which can take multiple content-types in request
text/plain
application/json
Now, client can send any of them either json or text.
I have two options available on server
I can create separate apis for different content types
I can parse request data and check if its json or text?
What is better approach here?Is there a design pattern suited for this need?
Note: Management prefer to have one api which can support multiple content-types.
The client must include a Content-Type header indicating the format of the entity they are sending to the server. If the server does not support the format which a client has sent, the expected response is 415 Unsupported Media Type.
I would go with option 1 and have the common logic placed in a seperate method. That way you let the API check and parse the input data for you.
In http you use the "accept"- header to define what type you expect the response to be. The server delivers the content as defined in accept header, the default if it's not set or 406 - "Not acceptable" if the type is not supported
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
One way would be to use #Path annotations more thoroughly-
The #javax.ws.rs.Path annotation must exist on either the class and/or a resource method. If it exists on both the class and method, the relative path to the resource method is a concatenation of the class and method.
See this link https://docs.jboss.org/resteasy/docs/1.1.GA/userguide/html/Using__Path_and__GET___POST__etc..html
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.
I am creating a Rest api using CXF. When I am trying to expose the Rest for a single record its working fine but if I try to send a Json array then it is showing:
JAXBException occurred : Too many closing tags.. Too many closing tags..
this exception. Don't have much idea what is the problem.
Check the class for the objects you're sending back doesn't have a field in there with the same name as the class. (If it does, try renaming the field ;).)