GetEntity vs ReadEntity in Response (Javax.ws.rs) - java

I am writing a client to consume a RestService and I have to read an entity out of the response and I am totally confused which method out of the two (getEntity vs readEntity) should be used.
I have to retrieve the entity whenever I get a WebApplicationException.
So, my code more or less looks like.
catch(WebApplicationException ex) {
// Do something with ex.getResponse
}
From, whatever I have tested,
ex.getResponse().hasEntity() ---> true
ex.getResponse().getEntity() == null ---> true
I don't know how it is working but if the first is true then how second statement could be true.
Surprisingly, readEntity worked fine for me and I was able to read the
entity out from the response.
But, after reading the entity through readEntity,
this call gives false.
ex.getResponse().getEntity() == null --> false
Can someone help me understand what is really happening behind the scenes?

The Response class has two uses: server side and client side. On the server side, it's called the outbound response. On the client, it's inbound response.
Outbound
#GET
public Response get() {
MyModel model = new MyModel();
return Response.ok(model).build();
}
Inbound
Response response = ClientBuilder.newClient().target(url).request().get();
The getEntity() method is meant to be used on the server side because you want to get the entity object. There's not much use for it for us, but Jersey will use it to get the entity object to serialize it before it sends it out.
The readEntity() method is to be used on the client side because you are trying to read the entity stream. If you try to call this on the server side, you will get an error saying that you can't read the stream on an outbound response.
As far as the behavior you're experiencing, I can't really explain why they implemented like this.

This behaviour is documented in the API:
public abstract <T> T readEntity(Class<T> entityType)
Read the message entity input stream as an instance of specified Java type using a MessageBodyReader that supports mapping the message entity stream onto the requested type.
[...]
A message instance returned from this method will be cached for subsequent retrievals via getEntity().
The first call to ex.getResponse().getEntity() is null, because the Entity hasn't been read yet. After calling readEntity(), the parsed entity will be returned as parsed by getEntity().

Related

SPRING - Can't retrieve a ResponseEntity with Feign while sent correctly formated

I'm trying to communicate information between two micro services in Spring. One is sending a ResponseEntity with an Object in the body, but on the other side I can't seem to get the correct response. All the fields are null.
this is the controller of my first microservice
this is what is returned when called directly
this is the code inspection of the response before it's sent
Then I try to recuperate this response in another micro service.
This is the client
This is the call to the first API
This is the response I get
So I'm stuck there, not getting why my client can't access the data. I have set breakpoints in both of the application and the first one is correctly called.
You can find my code there : https://github.com/Shikatamo/B3Examples
I have tried for 3-4h, and I'm really stuck there. It looks like something really stupid from my part but I can't seem to put my finger on it. All help is greatly appreciated at this point.
Try to get rid of ResponseEntity in your client:
#Component
#FeignClient("CourseStudent")
public interface ICourseStudentClient {
#RequestLine("GET /{id}")
CourseStudents getOneById(#Param("id") Long id);
}

Spring HttpClientErrorException provides no details from response body

I'm updating legacy code that uses the exchange method of Spring 3.1 Framework's RestTemplate class. I came across what appears to be a major omission of detail. When the rest client with which I am attempting to communicate returns a 400 status code, a HttpClientErrorException is thrown but there is no response body to provide detail as to why the server rejected the request. There looks like there is no way to retrieve the response body which would provide very helpful information.
I do not need to figure out what is wrong in my calling code as I have already done that. I just would like to know if there is some way I could access and log the body of the HTTP response if an error occurs on the call.
The response body is actually a property on HttpClientErrorException. It can be accessed via the following two accessors which it inherits from its parent class HttpStatusCodeException:
public byte[] getResponseBodyAsByteArray()
public String getResponseBodyAsString()
Cast your HttpClientErrorException e to HttpStatusCodeException:
((org.springframework.web.client.HttpStatusCodeException) e).getResponseBodyAsString()

In REST / Java, what should I return if my object is null?

I have a simple POJO that I annotated with REST annotations as follows:
#GET
#Path("/domains/{domainid}")
#Override
public Domain getDomain(#PathParam("domainid") UUID domainID) throws Exception {
logger.info("Retrieving domain "+ domainID);
Domain d = null;
try {
d = MyClient.getDomains().get(domainID.toString());
logger.debug("Returning "+d.getName());
} catch (Exception e) {
logger.error("Could not retrieve domain", e);
}
return d;
}
Note that the log statement including d.getName() can actually throw an NPE which is then caught and logged. That's not pretty but it's also not the point here.
Ultimately whether d has a value or not, I return it.
In the case of a null value, my client receives an HTTP 204 status code. This is what wget displays: HTTP request sent, awaiting response... 204 No Content
Oddly enough, my browsers don't budge an inch. They still display the previous page (I suppose it makes sense to stay put when no content is received). I would have expected a blank page.
Three questions:
is HTTP 204 the right response to be returned?
how can I control that via annotations? Via other configuration?
what is the standard REST best practice regarding null objects?
Thanks
EDIT
There is a great question on the very same topic here: Is it correct to return 404 when a REST resource is not found?
If the request is trying to GET/locate/find a resource, and it can't be found, traditionally, we should send a 404 Not Found. For further discussion see here.
That being said, I generally like to have my resource methods return Response, as it's easier to fine tune the response the way I want (a little - not much - more detail here). But seeing as how your method is overriding an interface contract (and returning a model object), JAX-RS gives us a nice hierarchy of exceptions that will get mapped to a particular response/status. The list can be seen here.
So in your particular case, if the resource can't be found, you can throw a WebApplicationException(Response.Status.NOT_FOUND) or a NotFoundException, and the exception will be mapped to a 404 Not Found. Something like
d = MyClient.getDomains().get(domainID.toString());
if (d == null) {
throw new NotFoundException(); // <-- JAX-RS 2.0
// or throw new WebApplicationException(Response.Status.NOT_FOUND);
// ^^ JAX-RS 1.x
}
The method will exit when the exception is thrown, and the client will receive a response with a 404 Not Found status.
Related Q&As
How to catch 404 (NotFoundException) without being dependant on a JAX-RS implementation?
Is it correct to return 404 when a REST resource is not found?
EDIT
In the first line I stated "If the request is trying to GET/locate/find a resource..", but really, this applies to almost all cases we are using URI templates, whether it is for a GET, POST, PUT, DELETE, whatever. Consider this example
#PUT
#Path("/customers/{id}")
public Response updateCustomer(#PathParam("id") long id, Customer customer) {
...
}
Here is a method that allows the client to update a customer via a PUT. The client should know the complete URI to the resource before trying to update it. If the {id} parameter (used for lookup) is not found say in a database, then the resource doesn't exist, and a 404 Not Found should also be returned to the client.

Jersey RESTful Services: Resources & Responses

I see a lot of Jersey-based web services consisting of 1+ WebResources that have 1+ endpoints/methods like so:
package com.myws.fizz;
public class FizzResource {
#GET
#Path("/fizz/{id}")
public Response getFizzById(#PathParam("id") Long id) {
// ...etc.
}
#GET
#Path("/fizz")
public Fizz getFizzByFoo(Foo foo) {
// ...etc.
}
}
package com.myws.buzz;
public class BuzzResource {
#POST
#Path("/buzz")
public Response createBuzz(Buzz buzz) {
// ...etc.
}
}
I'm confused with what Jersey considers a "resource". Is there a relationship between a "resource" and a database? A table? A POJO?
When do you return a Response vs. a POJO? Look at my 2 getFizz methods above. When do I return a Fizz and when do I return a Response?
The term "Resource" isn't so much just a Jersey term, as it is a REST term. When dealing with REST, we have Resources and Representations. A resource can be anything, and in this context, it is some object located on the server, with a URL location. When a client requests for a resource, we send back a representation of it. You ask:
Is there a relationship between a "resource" and a database? A table? A POJO?
It could be a database (that's a thing). And we could simply represent it as a JSON object with the name of the database. Also it could be a table (that's a thing). And we could represent it as a JSON object with the name and column names. It could be a row in a table, and we could represent that with a JSON object with the column names as the keys and the row values as the JSON values. It could be a web page, an image, whatever. So hopefully you get the point that a resource can be anything. What we send back is its representation.
But the term resource is not just limited to returning something to a client request. The client could also send us a representation of a resource, to say create a new resource (POST) or change an existing resource (PUT). The client may send us a JSON representation of a row (resource) in our database.
When do you return a Response vs. a POJO? Look at my 2 getFizz methods above. When do I return a Fizz and when do I return a Response?
Returning Response allows you to fine tune the Response. When the client make a request, they always get back a response. Responses have headers, and entity bodies. When the return type of the resource method is Fizz, you are saying the entity body type will be a Fizz type. When the method returns, what actually happens is that the Fizz object isn't directly returned to the requesting client, all by itself. Behind the scenes, it gets wrapped in a Response that get's sent back to the client. The framework will set the headers it feels appropriate.
So whether we decide to return a Response or Fizz, it will get wrapped in a Response. And like I said, when we return a Response, it allows us to fine tune the Response, adding our own headers, status codes and such. For example, say someone make a POST. You could do something like
#POST
#Path("/buzz")
#Produces(...)
public Response createBuzz(Buzz buzz, #Context UriInfo uriInfo) {
int buzzID = // create buzz and get the resource id
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(buzzId)); // concatenate the id.
return Response.created(builder.build()).build();
}
Basically what this does is create the resource, say in the database, and we get a return id. We can use the id to concatenate to the URI to the id, this will be the new resource location. In terms of the Response, .created(...) is saying that the status code should be 201 Created, and the value we pass to the created method is the location of the newly created resource. This location will be set as the Location header in the response. So lets say that the path to the POST request is http://blah.com/buzz. What we would send back is http://blah.com/buzz/100, where 100 is the buzzId, and this complete URL is how we will access the buzz resource say with a GET requesst to a resource method annotated with say #GET #PATH("/buzz/{id}")
In terms of a GET, with a Response, we could do
Fizz newFizz = fizzService.getFizz();
return Response.ok(newFizz).build(); // sends the Fizz as the entity body
This is really not so much different than just returning the newFizz from the method, because we aren't doing anything special with the Response. We're just saying the status code should be 200 OK and attaching the entity body. This is what normally happens with a successful GET request. So if we just return the Fizz, instead of a Response, in the case of a successful GET, the framework will implicitly attach a 200 OK status.
Personally, I prefer to return Responses, because of the fine tuning factor.

CXF Rest Client - set ResponseReader for POJO (JAXBElement)

I want to transfer a POJO Object with my CXF Rest Client. It already works for JAXB annotated objects. So I had a lot attempts for it.
I tried
reader.setEntityClass(ObjectPOJO.class);
and something like
reader.setEntityClass(JAXBElement<ObjectPOJO>.class);
Both doesnt work. For the second attempt the code is wrong. I dindt get it to set the entity class to jaxbelement. Maybe it works with it.
After sending the object with:
Response response = client.path(PATH).post(new JAXBElement<ObjectPOJO>(new QName("pojo"), ObjectPOJO.class, pojoObject));
i tried to get my entity with different attempts. Something like:
ObjectPOJO pojo = ((JAXBElement<TenantPOJO>) res.getEntity()).getValue();
Does someone know if I have to register the ObjectPOJO.class or the JAXBElement.class. If second attempt is right, how does it look right in code?
Whats the right code to get the entity out of the response?
My Service looks like this:
#POST
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response postPojo(JAXBElement<ObjectPOJO> pojo);
Edit:
Error
ERROR org.apache.cxf.jaxrs.client.AbstractClient - .Problem with reading the response message, class : class javax.ws.rs.core.Response, ContentType : application/xml.
To transfer objects (PoJos) between rest clients and rest services, there is no need to transfer it using the explicit JAXB conversion. The Jersey container is responsible for the necessary conversion provided the transfer objects are JAXB Annotated Objects.
Response response = client.path(PATH).post(postObject);
#XmlRootElement
public class PostObject
{
////
}

Categories

Resources