Get status for a PUT request on Jersey client - java

I have a webservice defined with Jersey in the server side like this:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Path("/foo")
public Response bar(List<Foo> listFoo) {
try {
//save the resource
} catch (Exception e) {
log.error("Error saving", e);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
return Response.status(Status.OK).build();
}
I am trying to get the server status in my Jersey client like this:
Response response = ws.type(MediaType.APPLICATION_XML).post(Response.class,list);
But I get the error:
A message body reader for Java class javax.ws.rs.core.Response, and Java type class javax.ws.rs.core.Response, and MIME media type application/xml was not found javax.ws.rs.core.Response
I don't really need the Response object, just the status code, how could I get it?

Ok, I solved it by changing the request response type:
Response response = ws.type(MediaType.APPLICATION_XML).post(Response.class,list);
with
ClientResponse response = ws.type(MediaType.APPLICATION_XML).post(ClientResponse.class,list);
being ClientResponse a com.sun.jersey.api.client.ClientResponse

Add #Consumes annotation to your web-serivce and the parameter to your bar() method, because you are trying to put there some object named list.
And I would recommend you to use #POST instead, because canonical #PUT does not return a response.
UPD. By the way, you have your entity empty - you should better remove your #Produces annotation and just return Response with its status set.
UPD2. and remove .accept(MediaType.APPLICATION_XML) method from client side.

Related

How to get request body of POST request using REST API in java

I am using javax.ws.rs.* classes for REST API.
HttpConnection Class and URLConnection for connection.
I have one method As
#POST
#Path("/{containerId}/{caseDefId}/customcasestart")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response claimTasks(#Context HttpHeaders headers, #PathParam("containerId") String containerId,
#PathParam("caseDefId") String caseDefId,String payload) {}
{
logger.info("Payload : "+payload)
}
This payload is not fetching data from request body .
I am passing data from postman-Body-Raw as Follow :
{
"userId":"123",
"date":"2020/07/15"
}
But it gives null. And I have no idea how to fetch body parameter using any method or class?
Anyone please help here.

Spring return JSON for HTTP 406 (NOT_ACCEPTABLE)

Spring allows the definition of #ExceptionHandlers inside of #RestControllerAdvice.
I already defined a lot of other ExceptionHandlers in there for HTTP 400, 404, 405,... However the ExceptionHandler for HTTP 406 (NOT_ACCEPTABLE) does not seem to work. The handler is triggered, I checked that in the logs, but the result is not used.
My goal is it to return a HTTP 406 with a JSON body.
Variant 1
#ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
#ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ErrorDTO requestMethodNotSupported(final HttpMediaTypeNotAcceptableException e) {
final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
return dto;
}
Variant 2
#ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<ErrorDTO> requestMethodNotSupported2(final HttpMediaTypeNotAcceptableException e) {
final ErrorDTO dto = new ErrorDTO(HttpStatus.NOT_ACCEPTABLE, "http.media_not_acceptable");
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).contentType(MediaType.APPLICATION_JSON_UTF8).body(dto);
}
But I always get a HTML response similar to this from the Tomcat:
HTTP Status 406 -
type: Status report
message:
description: The resource identified by
this request is only capable of generating responses with
characteristics not acceptable according to the request "accept"
headers.
instead of
{
"errorCode": 406,
"errorMessage": "http.media_not_acceptable"
}
Request-Headers:
Accept: application/stuff-that-cannot-be-present
Actual-Response-Headers:
Content-Type: text/html
Expected-Response-Headers:
Content-Type: application/json
I know that I could simply "fix" the Accept-Header that is send by the client, however the server should always respond in JSON, if it does not know how to respond.
I use Spring 4.3.3.RELEASE and Jackson 2.8.4.
Finally I found a solution for this:
Instead of returning a serializable object just return the bytes directly.
private final ObjectMapper objectMapper = new ObjectMapper();
#ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public ResponseEntity<byte[]> mediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException e) {
Object response = ...;
try {
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(objectMapper.writeValueAsBytes(response));
} catch (Exception subException) {
// Should never happen!!!
subException.addSuppressed(e);
throw subException;
}
}
EDIT:
As an alternative you can create a custom HttpMessageConverter<ErrorResponse> for your ErrorResponse object.
Go to your or create a impl of WebMvcConfigurerAdapter#extendMessageConverters(converters)
Pick a HttpMessageConverter that is capable of creating your expected result/content type.
Wrap it in a way to fulfill the following conditions:
getSupportedMediaTypes() returns MediaType.ALL
canRead() returns false
canWrite()returns only true for your ErrorResponse
write() sets the forced CT and forward your expected content type to the wrapped converter.
Add your wrapper to the converters list.
If added as first element then it will always return your expected result (forced)
Requested: json , Returned: forced CT
Requested: xml , Returned: forced CT
Requested: image , Returned: forced CT
If added as last element then it will only return the result as your expected result, if there was no other matching converter (fallback)
Requested: json , Returned: json
Requested: xml , Returned: xml
Requested: image , Returned: forced CT
Building on #ST-DDT findings. If you are also extending ResponseEntityExceptionHandler then you cannot just add another method to handle HttpMediaTypeNotAcceptableException. However, there is an even simpler solution to the whole problem then:
#Override
public ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ResponseEntity<Object> response = super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request);
// Workaround to return JSON response for 406
return ResponseEntity.status(NOT_ACCEPTABLE)
.contentType(APPLICATION_JSON)
.body(response.getBody());
}

restful web services: HTTP Status 500.The server encountered an internal error that prevented it from fulfilling this request error

I write a rest ful web service that has formParam and return a list . and I test it in postman . but I get this error.HTTP Status 500.The server encountered an internal error that prevented it from fulfilling this request error.
here is my service :
#Path("/report")
public class weightingResource {
#POST
#Path("/loadWeightingByPlate")
//#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public List<Weighting> LoadWeightingInSpecTimeInSpecPlate(
#FormParam("plate") String plate,
#FormParam("startTime") String _startTime,
#FormParam("endTime") String _endTime,
#Context HttpServletRequest req) {
Long startTime = new Long(_startTime);
Long endTime = new Long(_endTime);
try {
List<Weighting> weightings = Weighting.LoadWeightingInSpecTimeInSpecPlate(startTime, endTime, plate);
System.out.println("no error");
return weightings;
} catch (Exception ex) {
System.out.println("Exception = " + ex);
return null;
}
}
}
I test Weighting.LoadWeightingInSpecTimeInSpecPlate(startTime, endTime, plate) and this work correctly . can eny one help me ?
stack trace :
Blockquote21-Aug-2015 17:44:31.133 WARNING [http-nio-8084-exec-197] org.glassfish.jersey.servlet.WebComponent.filterFormParameters A servlet request to the URI http://127.0.0.1:8084/fsc-access/rest/report/loadWeightingByPlate contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.
21-Aug-2015 17:44:31.210 SEVERE [http-nio-8084-exec-197] org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List.
now my service works well and
I write a client to use this service but I get an error : HTTP 400 Bad Request :javax.ws.rs.BadRequestException
String webserviceURI = "http://localhost:8084/fsc-access";
ClientConfig clientConfig = new ClientConfig();
Client client = ClientBuilder.newClient(clientConfig);
URI serviceURI = UriBuilder.fromUri(webserviceURI).build();
WebTarget webTarget = client.target(serviceURI);
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("plate", plate);
formData.add("startTime", start.toString());
formData.add("endTime", end.toString());
Weightings weightings = new Weightings();
weightings.getWeightings().addAll((Collection<? extends Weighting>) webTarget.path("rest").path("report").path("loadWeightingByPlate").
request().accept(MediaType.APPLICATION_XML).post(javax.ws.rs.client.Entity.form(formData), Weightings.class));
how I can fix it ?
First, the reason you're getting the 500 is told by the following message:
21-Aug-2015 17:44:31.210 SEVERE [http-nio-8084-exec-197]
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo
MessageBodyWriter not found for media type=application/xml, type=class
java.util.ArrayList, genericType=java.util.List.
That indicates that Jersey, your servlet, does not have a registered MessageBodyWriter that returns true from isWritable() with the following parameters
media type=application/xml,
type=class java.util.ArrayList,
genericType=java.util.List
AFAIK Jersey usually has access to a JAXB implementation, but some JAXB implementations cannot handle generics like List correctly. What I would suggest is that you create a new class called Weightings that is a list wrapper for a collection of Weighting objects. This is a common thing to do with JAXB models.
#XmlRootElement
public class Weightings {
#XmlElement
private final List<Weighting> weightings = new ArrayList<Weighting>();
public List<Weighting> getWeightings() {
return weightings;
}
}
Then modify your resource to return the new type:
#POST
#Path("/loadWeightingByPlate")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Weightings LoadWeightingInSpecTimeInSpecPlate(
#FormParam("plate") String plate,
#FormParam("startTime") String _startTime,
#FormParam("endTime") String _endTime,
#Context HttpServletRequest req) {
Long startTime = new Long(_startTime);
Long endTime = new Long(_endTime);
try {
Weightings weightings = new Weightings();
weightings.getWeightings().addAll( Weighting.LoadWeightingInSpecTimeInSpecPlate(startTime, endTime, plate));
System.out.println("no error");
return weightings;
} catch (Exception ex) {
System.out.println("Exception = " + ex);
return null;
}
}
That should fix your 500 response. Your other option is to look around and test other JAXB or application/xml MessageBodyWriter implementations that might support generics better.
The other warning you're getting:
21-Aug-2015 17:44:31.133 WARNING [http-nio-8084-exec-197]
org.glassfish.jersey.servlet.WebComponent.filterFormParameters A
servlet request to the URI
http://127.0.0.1:8084/fsc-access/rest/report/loadWeightingByPlate
contains form parameters in the request body but the request body has
been consumed by the servlet or a servlet filter accessing the request
parameters. Only resource methods using #FormParam will work as
expected. Resource methods consuming the request body by other means
will not work as expected.
I would take a look at this question if you're interested in fixing the warning.

Error message in REST webservices

I am calling REST webservices from JSP using AJAX . Can you tell me the best way to send custom error message from REST webservice to JSP ?
Consider using HTTP response codes with (possibly) json response bodies to supply any required information so the client application can react accordingly.
Consider using the WebapplicationException. You can give it the Errorcode (also custom ones) and a body for the response. You could use the JSON Format if you have a complex structure to display your errors but i would suggest just using the an errormessage (for example in case of a bad request, what part of the request was bad).
If you are using JAX-RS REST webservice, you can configure Spring #Controller. Your method should produce application/json and return Response object, like in this example:
#GET
#Path("/get/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserById(#PathParam("id") String userId) {
// Here your logic
Foo foo = new Foo();
foo.setMsg("Bad Request");
foo.setData("User " + userId + " not found")
return Response.status(400).entity(foo).build();
}
And from AJAX, you can catch error message
// Get user details
$.getJSON(encodeURI("./rest/user/get/" + userId), function(data) {
// Some logic on success
// Fail
}).fail( function(jqxhr) {
console.log(jqxhr.responseJSON.msg);
});
There are a couple of ways.
1. You can look at the response status you receive from the web service. The statuses starting with 2** are a success response (Eg: 200, 201), the ones starting with 4** or 5** are errors.
But the optimal way to handle and track exceptions is to use ExceptionMapper. You can write your own class that implements ExceptionMapper like below:
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}
You can write your own custom exceptions like below or can throw blanket exception like below. The above approach is the preferred one though.
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}

How to consume json parameter in java restful service

How can i consume json parameter in my webservice, I can able to get the parameters using #PathParam but to get the json data as parameter have no clue what to do.
#GET
#Path("/GetHrMsg/json_data")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces(MediaType.APPLICATION_JSON)
public String gethrmessage(#PathParam("emp_id") String empid) {
}
What to use in place of #PathParam and how to parse it later.
I assume that you are talking about consuming a JSON message body sent with the request.
If so, please note that while not forbidden outright, there is a general consensus that GET requests should not have request bodies. See the "HTTP GET with request body" question for explanations why.
I mention this only because your example shows a GET request. If you are doing a POST or PUT, keep on reading, but if you are really doing a GET request in your project, I recommend that you instead follow kondu's solution.
With that said, to consume a JSON or XML message body, include an (unannotated) method parameter that is itself a JAXB bean representing the message.
So, if your message body looks like this:
{"hello":"world","foo":"bar","count":123}
Then you will create a corresponding class that looks like this:
#XmlRootElement
public class RequestBody {
#XmlElement String hello;
#XmlElement String foo;
#XmlElement Integer count;
}
And your service method would look like this:
#POST
#Path("/GetHrMsg/json_data")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void gethrmessage(RequestBody requestBody) {
System.out.println(requestBody.hello);
System.out.println(requestBody.foo);
System.out.println(requestBody.count);
}
Which would output:
world
bar
123
For more information about using the different kinds of HTTP data using JAXB, I'd recommend you check out the question "How to access parameters in a RESTful POST method", which has some fantastic info.
Bertag is right about the comment on the GET. But if you want to do POST request that consumes json data, then you can refer to the code below:
#POST
#Path("/GetHrMsg/json_data")
#Consumes(MediaType.APPLICATION_JSON)
public Response gethrmessage(InputStream incomingData) {
StringBuilder crunchifyBuilder = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incomingData));
String line = null;
while ((line = in.readLine()) != null) {
crunchifyBuilder.append(line);
}
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
System.out.println("Data Received: " + crunchifyBuilder.toString());
// return HTTP response 200 in case of success
return Response.status(200).entity(crunchifyBuilder.toString()).build();
}
For referencing please click here
#PathParam is used to match a part of the URL as a parameter. For example in an url of the form http:/example.com/books/{bookid}, you can use #PathParam("bookid") to get the id of a book to a method.
#QueryParam is used to access key/value pairs in the query string of the URL (the part after the ?). For example in the url http:/example.com?bookid=1, you can use #QueryParam("bookid") to get the value of `bookid.
Both these are used when the request url contains some info regarding the parameters and you can use the data directly in your methods.
Please specify the problem in detail if this post doesn't help you.

Categories

Resources