Consider the following code with JAXB binding,
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class SomeRequest {
#XmlElements(value={#XmlElement(name="objOne", type="ObjectOne.class"),
#XmlElement(name="objTwo", type="ObjectTwo.class")})
private MyObject obj;
}
When I get a request similar to this,
<request>
<objectOne>
<!-- Some Data -->
</objectOne>
<objectTwo>
<!-- Some data -->
</objectTwo>
</request>
Both the values are unmarshalled and processed, but only the last value of objectTwo remains.
I want to avoid this some way, by throwing an exception when both are sent in the request.
Also, I am looking for a way to solve it programmatically, without using wsdl schema validation..
I have tried to use, JAXB XmlAdapter after looking at the following question,
Confused as how to use JAXB XML Adapter for my requirement but there is no way to compare if the object has already a value and throw a soap fault.
I also couldn't think of a way of solving it using Unmarshaller, from the oracle jaxb docs
If you could recommend a solution using some kind of Interceptor or extending some JAXB class and validate and throw an exception, it would be great.
The web service implementation is done using apache cxf on jboss, if it helps. CXF Interceptors are also an option but I would take that only if there is no JAXB related solution.
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
I'm trying to setup a REST-service with Jersey 2.x that consumes a JSON-Response by POST using MOXy.
Everything works fine as long as all the JSON-attributes are named exactly like the properties in my POJO. Is there any way to configure MOXy so that it allows case-insensitive unmarshalling? For example: Match JSON-attribute "testid" to "TestID" in my POJO.
The POJO-Field is camel case, but the incoming JSON-Attribute could be in any case and my sevice should be able to process it nonetheless.
Thank you for your help!
Without defining a custom unmarshaller (or parsing directly from the HttpServletRequest) you can only define the expected key name, as pointed out in the comment of rmlan, with the JAXB annotation #XmlElement(name="testid"). However this will not protect your service from a JSON input with a key like "TestID" or "TESTID".
Having a SOAP based web service with XML payload, how can I grab the XML payload of the service response in JAX-WS >2.0 client?
I can see how this question will be marked as duplicate, but bear with me.
It seems that the options are:
Use Dispatch API. However this would require me to go low(er) level and create the request payload manually, which I want to avoid.
Use handler infrastructure of the JAX-WS to grab the payload and possibly pass it via MessageContext property back to the client, but this will still unmarshall the XML into JAXB Object tree, which I want to avoid.
So, how can I:
Call a web service using SEI - no messing with creating XML request from scratch
Grab the 'RAW' XML response without the JAXB unmarshalling happening
Sounds simple enough, right?
Among the non-goals the JAX-WS 2 specification says that
'Pluggable data binding JAX-WS 2.0 will defer data binding to JAXB[10]; it is not a goal to provide a
plug-in API to allow other types of data binding technologies to be used in place of JAXB. However,
JAX-WS 2.0 will maintain the capability to selectively disable data binding to provide an XML based
fragment suitable for use as input to alternative data binding technologies.'
So, you should be able to have access to the raw payload.
The following example is also in the specification :
4.3.5.5 Asynchronous, Callback, Payload-Oriented
class MyHandler implements AsyncHandler<Source> {
...
public void handleResponse(Response<Source> res) {
Source resMsg = res.get();
// do something with the results
}
}
Source reqMsg = ...;
Service service = ...;
Dispatch<Source> disp = service.createDispatch(portName,
Source.class, PAYLOAD);
MyHandler handler = new MyHandler();
disp.invokeAsync(reqMsg, handler);
Since the specification also states that a Binding has its own HandlerChain (see chapter 9) you should be able to remove the JAXB handler from the chain, so that JAXB marshalling/unmarshalling doesn't get involved.
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.
Goal
Java client for Yahoo's HotJobs Resumé Search REST API.
Background
I'm used to writing web-service clients for SOAP APIs, where wsimport generates proxy stubs and you're off and running. But this is a REST API, which is new to me.
Details
REST API
No WADL
No formal XML schema (XSD or DTD files). There are example XML request/response pairs.
No example code provided
Progress
I looked at question Rest clients for Java?, but the automated solutions there assume you are providing both the server and the client, with JAXB invoked on POJOs to generate a schema and a REST API.
Using Jersey (a JAX-RS implementation), I have been able to make a manual HTTP request:
import com.sun.jersey.api.client.*;
...
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("https://hj.yahooapis.com/v1/HJAuthTokens");
webResource.accept("application/xml");
// body is a hard-coded string, with replacements for the variable bits
String response = webResource.post(String.class, body);
// parse response into a org.w3c.dom.Document
// interface with Document via XPATH, or write my own POJO mappings
The response can look like:
<?xml version="1.0" encoding="utf-8"?>
<Response>
<ResponseCode>0</ResponseCode>
<ResponseMessage>Login successful</ResponseMessage>
<Token>NTlEMTdFNjk3Qjg4NUJBNDA3MkJFOTI3NzJEMTdDNDU7bG9jYWxob3N0LmVnbGJwLmNvcnAueWFob28uY29tO0pVNWpzRGRhN3VhSS4yQVRqRi4wWE5jTWl0RHVVYzQyX3luYWd1TjIxaGx6U0lhTXN3LS07NjY2MzM1OzIzNDY3NTsxMjA5MDE2OTE5OzZCM1RBMVNudHdLbl9VdFFKMFEydWctLQ==</Token>
</Response>
Or, it can look like:
<?xml version="1.0" encoding="utf-8"?>
<yahoo:error xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" xml:lang="en-US">
<yahoo:description>description</yahoo:description>
<yahoo:detail>
<ErrorCode>errorCode</ErrorCode>
</yahoo:detail>
</yahoo:error>
Questions
Is there a way to auto-generate POJOs which can be marshalled/unmarshalled without a formal schema?
Should I attempt to generate those POJOs by hand, with JAXB annotations?
Is there some tool I should be leveraging so I don't have to do all this manually?
It's interesting that they provide an HTTP URL as the namespace URI for the schema, but don't actually save their schema there. That could be an oversight on their part, which an email or discussion-list posting could correct.
One approach is to create your own schema, but this seems like a lot of work for little return. Given how simple the messages are, I wonder if you even need a POJO to wrap them? Why not just have a handler that extracts the data you need using XPath?
Edit: blast from the past, but I saw the comment, reread the question, and realized that the first sentence was hard to understand. So, clarification:
One very good habit, if you're going to write a publicly accessible web service, is to make your schema document available at the same URL that you use for the schema's namespace URI -- or better, have that URL be a link to complete documentation (the W3C XSD namespace is itself a good example: http://www.w3.org/2001/XMLSchema).
I would suggest writing beans by hand, and only annotating with JAXB annotations if you have to. For most accessors/mutators (getters/setters) you do not have to; by default all public bean accessors and fields are considered, name is derived using bean convention, and default is to use elements instead of attributes (so attributes need to be annotated).
Alternatively you can of course write schema by hand, generate beans using JAXB, if you like W3C Schema a lot. And just use resulting code, not schema, for data binding.
As to POJO: that can be very simple. Something like:
#XmlRootElement("Response")
class Response {
public int responseCode;
public String responseMessage;
public String token; // or perhaps byte[] works for automated base64?
}
and similarly for other ones. Or, use getters/setters if you like them and don't mind bit more verbosity. These are just data containers, no need to get too fancy.
And if you must auto-detect type from content, consider using Stax parser to see what the root element, and then bind using JAXB Unmarshaller, handing XMLStreamReader that points to that root element. That way you can pass different object type to bind to.
And finally: sending/receiving requests: plain old HttpURLConnection works ok for GET and POST requests (construct using, say, URL.openConnection()). Jakarta HttpClient has more features if need be. So oftentimes you don't really need a separate REST client -- they may come in handy, but generally build on simple http client pieces.
I find HTTP4E very useful for making REST calls. It is an awesome Eclipse plugin, it has tabs, syntax coloring, auto suggest, code generation, REST HTTP call replay, etc.. It does a great job of HTTP debugging, HTTP tampering, hacking. I am having so much fun with it.
http://www.ywebb.com/
Try JdkRequest from jcabi-http (I'm a developer). This is how it works:
String body = new JdkRequest("http://www.google.com")
.header("User-Agent", "it's me")
.fetch()
.body()
Check this blog post for more details: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html