Get answer from rest server with javax.ws.rs.client [duplicate] - java

Having some sort of proxy between a mobile app and a web-service, we are puzzled by the response when issuing a post request. We receive response with status 200: OK. But we can not find/extract the JSON response body.
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(WEBSERVICE_BASE_LOCATION + "mobileDevices?operatorCode=KPNSCP");
String jsonString = "{\"osVersion\":\"4.1\",\"apiLevel\":16,\"devicePlatform\":\"ANDROID\"}";
Builder builder = webTarget.request();
Response response = builder.post(Entity.json(jsonString));
We are using JAX-RS.
Can someone please provide some hints to extract the JSON body (String) from the server response?

Try this:
String output = response.getEntity(String.class);
EDIT
Thanks to #Martin Spamer to mention that it will work for Jersey 1.x jars only. For Jersey 2.x use
String output = response.readEntity(String.class);

I just found a solution for jaxrs-ri-2.16 - simply use
String output = response.readEntity(String.class)
this delivers the content as expected.

For my use case, none of the previous answers worked because I was writing a server-side unit test which was failing due the following error message as described in the Unable to Mock Glassfish Jersey Client Response Object question:
java.lang.IllegalStateException: Method not supported on an outbound message.
at org.glassfish.jersey.message.internal.OutboundJaxrsResponse.readEntity(OutboundJaxrsResponse.java:145)
at ...
This exception occurred on the following line of code:
String actJsonBody = actResponse.readEntity(String.class);
The fix was to turn the problem line of code into:
String actJsonBody = (String) actResponse.getEntity();

I also had the same issue, trying to run a unit test calling code that uses readEntity. Can't use getEntity in production code because that just returns a ByteInputStream and not the content of the body and there is no way I am adding production code that is hit only in unit tests.
My solution was to create a response and then use a Mockito spy to mock out the readEntity method:
Response error = Response.serverError().build();
Response mockResponse = spy(error);
doReturn("{jsonbody}").when(mockResponse).readEntity(String.class);
Note that you can't use the when(mockResponse.readEntity(String.class) option because that throws the same IllegalStateException.
Hope this helps!

Acording with the documentation, the method getEntity in Jax rs 2.0 return a InputStream.
If you need to convert to InputStream to String with JSON format, you need to cast the two formats.
For example in my case, I implemented the next method:
private String processResponse(Response response) {
if (response.getEntity() != null) {
try {
InputStream salida = (InputStream) response.getEntity();
StringWriter writer = new StringWriter();
IOUtils.copy(salida, writer, "UTF-8");
return writer.toString();
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
return null;
}
why I implemented this method.
Because a read in differets blogs that many developers they have the same problem whit the version in jaxrs using the next methods
String output = response.readEntity(String.class)
and
String output = response.getEntity(String.class)
The first works using jersey-client from com.sun.jersey library and the second found using the jersey-client from org.glassfish.jersey.core.
This is the error that was being presented to me:
org.glassfish.jersey.client.internal.HttpUrlConnector$2 cannot be cast to java.lang.String
I use the following maven dependency:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
What I do not know is why the readEntity method does not work.I hope you can use the solution.
Carlos Cepeda

Realizing the revision of the code I found the cause of why the reading method did not work for me. The problem was that one of the dependencies that my project used jersey 1.x.
Update the version, adjust the client and it works.
I use the following maven dependency:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.28</version>
Regards
Carlos Cepeda

Related

How to read body of HttpServletRequest multiple times?

Basically I need to read the body of HttpServletRequest multiple times, based on my research I found that one of easiest way for doing that is by using ContentCachingRequestWrapper
Here is how I implemented it:
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
try{
MultipartRequest multipartRequest = new MultipartRequest(requestWrapper, ImageDirecoty, 1024*1024*5);
String test = requestWrapper.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.print(test);
} catch(IOException e){
System.out.println(e.getMessage());
return;
}
FYI: I am uploading a simple file from my client to server.
Now at first it reads the request body just fine, but in the second line which I have String test = requestWrapper to read it's content and to output it to console I don't get my Ecplise console outputing me anything and I don't get any error too, I'd really appreciate if somebody tell me what am i doing wrong.
actually the easy est way to do it is to use(convert the response), to some kind of Pojo class, and then saving it to whatever you want.
here is a link to convert it to pojo
http://www.jsonschema2pojo.org/
also you can use library's like Retrofit 2.0 to make your http calls much easier.
http://square.github.io/retrofit/

File is not getting download using JERSEY

I am using jersey API in my project. I stuck in a case that file needs to be downloaded but it's not. My code is as follow
#GET
#Produces("application/download")
public Response downloadFile(){
String data = getDatas();
ResponseBuilder response = Response.ok(data);
response.header("Content-Disposition","attachment;filename=UserData.txt");
response.header("charset", "UTF-8");
return Response.build();
}
I have added all the packages, paths are also fine. No Error came.
When I call this API, data comes in the response. I want this data to be in a file and in a downloadable format.
I also tried #Produces(MediaType.APPLICATION_OCTET_STREAM).
Please correct me if am doing wrong
I think you are not sending the response you have build.
first you're using a ResponseBuilder to build the resposne
ResponseBuilder response = Response.ok(data);
response.header("Content-Disposition","attachment;filename=UserData.txt");
response.header("charset", "UTF-8");
then you are returning the static Response.build() (notice the capital R) object, which is empty
you should return response.build()
also, you should produce octet-stream in your method annotions
#Produces(MediaType.APPLICATION_OCTET_STREAM)
and not
#Produces("application/download")
refer to this question: what's the correct way to send a file from REST web service to client?

setting content type in rest assured

I'm trying to invoke a rest call using rest assured. My API accepts, "application/json" as content type and I need to set in the call. I set the content type as mentioned below.
Option 1
Response resp1 = given().log().all().header("Content-Type","application/json")
.body(inputPayLoad).when().post(addUserUrl);
System.out.println("Status code - " +resp1.getStatusCode());
Option 2
Response resp1 = given().log().all().contentType("application/json")
.body(inputPayLoad).when().post(addUserUrl);
The response I get is "415" (indicates that "Unsupported media type ").
I tried invoking the same api using plain java code and it works. For some mysterious reason, I cudn't get it working through RA.
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(addUserUrl);
StringEntity input = new StringEntity(inputPayLoad);
input.setContentType("application/json");
post.setEntity(input);
HttpResponse response = client.execute(post);
System.out.println(response.getEntity().getContent());
/*
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println("Output -- " +line);
}
I faced similar issue while working with rest-assured 2.7 version. I tried setting both the contentType and also accept to application/json but it didn't work. Adding carriage feed and new line characters at the end as the following worked for me.
RestAssured.given().contentType("application/json\r\n")
The API seems to be missing to add new line characters after Content-Type header due to which the server is not able to differentiate between the media type and the rest of the request content and hence throwing the error 415 - "Unsupported media type".
Here is the complete POST example using CONTENT_TYPE as JSON.
import io.restassured.http.ContentType;
RequestSpecification request=new RequestSpecBuilder().build();
ResponseSpecification response=new ResponseSpecBuilder().build();
#Test
public void test(){
User user=new User();
given()
.spec(request)
.contentType(ContentType.JSON)
.body(user)
.post(API_ENDPOINT)
.then()
.statusCode(200).log().all();
}
Give a try
given().contentType(ContentType.JSON).body(inputPayLoad.toString)
This might possibly be the case with your test. Try this.
https://github.com/rest-assured/rest-assured/wiki/Usage#avoid-adding-the-charset-to-content-type-header-automatically
Avoid adding the charset to content-type header automatically
By default REST Assured adds the charset header automatically. To
disable this completely you can configure the EncoderConfig like this:
RestAssured.config = RestAssured.config(config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false));
As mentioned in previous posts there is a method:
RequestSpecification.contentType(String value)
I did not work for me too. But after upgrade to the newest version (in this moment 2.9.0) it works. So please upgrade :)
I was facing something similar and after some time we noticed the problem was actually coming from the server side. Please check your call on Postman and see if when it's triggered you need to change it from HTML to JSON. If you need to do that, the backend may need to force the response to be in JSON format by adding its content type. Even if it's encoded in JSON you're still may need to do that.
Thats the line of code we added:
header('Content-type:application/json;charset=utf-8');
.
public function renderError($err){
header('Content-type:application/json;charset=utf-8');
echo json_encode(array(
'success' => false,
'err' => $err
));
}
And that's what was happening on the backend:
Hope that can help somehow. :)
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import static org.hamcrest.Matchers.is;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
public class googleMapsGetLocation {
#Test
public void getLocation() {
RestAssured.baseURI = "https://maps.googleapis.com";
given().param("location", "-33.8670522,151.1957362")
.param("radius", "500")
.param("key", "AIzaSyAONLkrlUKcoW-oYeQjUo44y5rpME9DV0k").when()
.get("/maps/api/place/nearbysearch/json").then().assertThat()
.statusCode(200).and().contentType(ContentType.JSON)
.body("results[0].name", is("Sydney"));
}
}
For your First option can you please try adding this header too and sending the request?
.header("Accept","application/json")

How to use fluent of Apache Components

I am trying to build an http POST using the examples of Apache Components (4.3) - http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/fluent.html. Unfortunately, I receive an error that I have not been able to find out how to solve.
I have used the former HttpClient before - so this is my first go with components.
Here is a snippet of the code:
String address = "http://1.1.1.1/services/postPositions.php";
String response = Request.Post(address)
.bodyString("Important stuff", ContentType.DEFAULT_TEXT)
.execute().returnContent().asString();
System.out.println(response);
and when I run that code I get an exception:
Exception in thread "main" java.lang.IllegalStateException: POST request cannot enclose an entity
at org.apache.http.client.fluent.Request.body(Request.java:299)
at org.apache.http.client.fluent.Request.bodyString(Request.java:331)
at PostJson.main(PostJson.java:143)
I have tried to build a form element as well and use the bodyForm() method - but I get the same error.
I had the same issue, the fix is to use Apache Client 4.3.1 which works.
It seems that the Request was changed:
in 4.3.1 they use public HttpRequestBase
in the latest release they use the package protected InternalHttpRequest
For the sake of completeness I am going to post the way to do it without using the Fluent API. Even if it doesn't answer the question "How to use fluent of Apache Components", I think it is worth to point out that the below, simplest case, solution works for versions which have the bug:
public void createAndExecuteRequest() throws ClientProtocolException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost(host);
httppost.setEntity(new StringEntity("Payload goes here"));
try (CloseableHttpResponse response = httpclient.execute(httppost)) {
// do something with response
}
}
In my case, downgrading was not an option, so this was the best solution.
I did some digging and can't see how it can work (you might have found a bug).
The error stems from line 300 in Request in the latest trunk version. There a check is done to see if this.request instanceof HttpEntityEnclosingRequest but that is never true because this.request is always set to an instance of InternalHttpRequest in the Request constructor at line 130, and InternalHttpRequest does not implement org.apache.http.HttpEntityEnclosingRequest`.

How to send a POST request with parameters to an endpoint via JBoss HttpRouter?

I'm working on an ESB project and I need to call a REST service using a POST request. HttpRouter seems to be the right way to do it since it supports both GET and POST methods but I can't find a way to inject parameters inside my call.
How can I do that ?
You can try Apache HTTP library. It's very easy to use and have comprehensive set of class needed to manipulate HTTP request.
Found the answer... It was pretty dumb. All you need to do is to inject parameters inside the Message object and they will be in the body of the request. Here is a sample code created by JBoss and found from a unit test of HttpRouter :
final ConfigTree tree = new ConfigTree("WrappedMessage");
tree.setAttribute("endpointUrl", "http://127.0.0.1:8080/esb-echo");
tree.setAttribute("method", "post");
tree.setAttribute("unwrap", "false");
tree.setAttribute("MappedHeaderList", "SOAPAction, Content-Type, Accept, If-Modified-Since");
HttpRouter router = new HttpRouter(tree);
Message message = MessageFactory.getInstance().getMessage(type);
message.getBody().add("bar");
Message response = router.process(message);
String responseBody = (String)response.getBody().get();
String responseStr = null;
if (deserialize)
responseStr = Encoding.decodeToObject(responseBody).toString();
else
responseStr = responseBody;
return responseStr;

Categories