I am creating a Server HealthCheck page. Most of the servers return JSONObject and I am able to easily parse it using:
String jsonText = readAll(br);
JSONObject json = new JSONObject(jsonText);
JSONObject resp = json.getJSONObject("Response");
Now my problem is the other servers that do not return JSON. Some are returning String, some pdf file some image and as all the responses are 200 OK I should return Positive healthcheck.
However I am using Future Threads and timing out my request after 4 secs. And all the servers which return anything other than JSON get stuck at " new JSONObject(jsonText);"
Is there any way I can check if the type of respone is JSON or not in Java?
Update:
I found my mistake - stupid one.
In the try catch block I am only catching IOException, which is not catching JSONException(and didnt show any error too - dunno y). I have added a new catch block for JSONException which works for my solution for now.
However, this isnt elegant solution, #Dave, #Radai and #Koi 's solutions is the right approach to go with.
Don't parse the string. Go back one step, and check the Content-Type header of the HTTP response. If the response contains JSON data, the Content-Type should be application/json (source).
Check the MediaType in the response using response.getMediaType(). If it is json it returns application/json.
This helped me;
if (response.getMediaType().isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
System.out.println("The media type matches application/json");
} else {
System.out.println("The media type does not match application/json");
}
Related
I'm trying to send an http request to bing's spell checking api using a GET request. I checked my parameters and headers on https://www.hurl.it/ and it returned a proper json with the spelling errors properly, however when I send the request from my java app it returns this json with NO spelling errors detected (therefore, text parameter HAS to be empty somehow). I'm definitely passing the correct key in the header because that part isn't sending an error and the code is 200 (success).
My string: "my funger is harting me"
My code returned:
{"_type":"SpellCheck","flaggedTokens":[]}
Hurl.it returned:
{
"_type":"SpellCheck",
"flaggedTokens":[
{
"offset":3,
"token":"funger",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"finger",
"score":0.903614003311793
}
]
},
{
"offset":13,
"token":"harting",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"hurting",
"score":0.903614003311793
}
]
}
]
}
This is my java code using Apache's HTTPClient library:
(note: "command.getAfter()" is the passed string I mentioned above. I debugged it and even hard coded a string to test it out. Same output obviously.)
HttpClient httpclient = HttpClients.createDefault();
try {
URIBuilder builder = new URIBuilder("https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/");
builder.setParameter("text", command.getAfter());
URI uri = builder.build();
HttpGet request = new HttpGet(uri);
request.setHeader("Ocp-Apim-Subscription-Key", "XXXXXXXX");
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
EDIT: It turns out the URI returned in the request object returns this:
https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=my+funger+is+harting+me
So the parameter is not empty? But when fed no text parameter in hurl.it, the api returns an error of no parameters. When the text parameter is a space " ", it returns an identical result to mine. Unsure what this means since the URI seems to be valid and not empty and my subscription key is working because i would get an error if it weren't...
EDIT: I'm starting to suspect the Apache library is ignoring the parameters I'm passing in HttpGet(uri). I'm unsure, but I'm going to try a different solution to send the request with a header and see what happens.
EDIT: I tried the following code below:
String url = "https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=" + command.getAfter().replace(" ", "+");
try {
URL request_url = new URL(url);
//URIBuilder uri = new URIBuilder("https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/");
//uri.setParameter("text", command.getAfter());
HttpURLConnection con = (HttpURLConnection) request_url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Ocp-Apim-Subscription-Key", Keys.BING_SPELL_CHECK_API);
con.setConnectTimeout(100000);
con.setReadTimeout(100000);
con.setInstanceFollowRedirects(true);
String theString = IOUtils.toString(con.getInputStream(), "UTF-8");
System.out.println(theString);
} catch (IOException e) {
e.printStackTrace();
}
It returned the same result as the Apache one... :/ What else should I try?
EDIT:
This is the output of the request as well:
https://api.cognitive.microsoft.com/bing/v5.0/spellcheck/?text=my+funger+is+hartingme - [Ocp-Apim-Subscription-Key: <XXXXXXXXXXXX>]
HTTP/1.1 200 OK - en_US
{"_type": "SpellCheck", "flaggedTokens": []}
I don't get it.... Why is the json outputted empty when hurl.it returns the correct json for this same request? Is this a java issue or something?
EDIT:
I just tried UniRest's api. Exact same result... What am I doing wrong here?!
I'm so lost...
Separate Issue:
I do want to note the following: When I set the bing api's version to 7.0, I get the following error:
Received http status code 401 with message Access Denied and body {"message":"Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription.","statusCode":401}
This is not the case with v5.0. I'm getting the correct key from my Azure portal. (The page called Keys and lists 2 keys you can use and regenerate)
Answer to getting v7.0 to work:
This is not the case with v5.0. I'm getting the correct key from my Azure portal. (The page called Keys and lists 2 keys you can use and regenerate)
You get 2 keys per version. So if you are seeing 2 keys, they are likely both for v5.0. It should explicitly mention v7.0.
There should be different sections, also with different endpoints.
Use these in combination with each other to get the desired result.
I'm testing REST API and while I make GET call to retrieve resources, it's resulting into 500 Internal Server Error and in output it's returning message which has media type application/json:
[
{
"messageType": "Some error type",
"messageText": "Some message text",
"moreInfo": "Some info"
}
]
Please make note that in above output, Json is inside []
I want to read value of messageText from above output response. I tried with -
JsonObject jsonObject = response.readEntity(JsonObject.class);
but it results in following error:
java.lang.IllegalStateException: Entity input stream has already been closed.
at org.glassfish.jersey.message.internal.EntityInputStream.ensureNotClosed(EntityInputStream.java:225)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:830)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:783)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:111)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:399)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108)
Could you please help me how can I read the message in output? I'm using Jersy library.
According to javaDoc, a call to readEntity closes the response entity, so when you make another readEntity call you get IllegalStateException.
Unless the supplied entity type is an input stream, this method
automatically closes the an unconsumed original response entity data
stream if open.
In my case, having the expression response.readEntity(String.class)
in the Expressions pane in the Debug perspective caused this exception when I ran the code in Debug mode. The evaluation of the expression consumed the entity and caused it to close.
I solved this by first doing the readEntity to a String entity and then using the Jackson ObjectMapper to actually deserialize to the target class.
Problematic code:
Transactions transObj = response.readEntity(Transactions.class);
Solution:
String stringEntity = response.readEntity(String.class);
Transactions transObj = objectMapper.readValue(stringEntity, Transactions.class);
It seems this problem arises when the JSON string in the response entity stream is very long or complex possibly requiring multiple interactions thereon. 'Deserializing' to a string seems to only require a single bite. Once you have the string (and Jackson or GSON) de-serialization to target entity takes place without touching the response.
Actually it is a issue with how are we defining the reference of Response object .
Solution is weird
Not Working one :
Response response;
if (condition) {
response =
} else {
response =
}
String resp = response.readEntity(String.class);
if (response.getStatus() == 200) {}
Working One
Response response = null;
if (condition) {
response =
} else {
response =
}
String resp = response.readEntity(String.class);
if (response.getStatus() == 200) {}
So basically if we wont assign anything to response initially , Stream will be closed
When you get your error 500 you probably get another exception in the console/log. You should start checking that and then trying to resolve this one. If you don't find anything in the log, could you please post more code?
I am getting different type of JSON response out of HTTP request API. There are might be couple of JSON format option coming back from API. For example it might be valid response with expected data but in some cases it might be internal server error detailed message.
At the moment I am using Gson to convert incoming string into the object, but since sometimes it comes as different format Gson not able to convert it as different template class is provided.
NOTE:
Error does not mean an exception. For example JSON body contain just information that authentication is failed for example, but call was made successfully and JSON body is VALID. HTTP is actually always successful and will be 200. Problem is that sometimes authentication might fail and it will return different JSON.
String response = restTemplate.getForObject(request, String.class);
ObjectResponse objResponse = gson.fromJson(response, ObjectResponse.class);
Could you please suggest better way of doing it so that I can handle different types of responses? Or maybe you know completely different way of doing it.
Thanks!
If you can't predict the structure of the response, map it to a tree of simple Java maps, arrays, and strings. The Jackson library supports this with 'readTree' methods. Once you look at the tree and decide what it is, you can then ask the library to map a tree to an object of a class.
One option is to make a class representing the JSON data, and deserialize into that. This way, if the data does not match that structure, you will get an exception.
When you try and create your object and it fails, catch the exception and try and decode it as an error - you can then deal with that case as you wish (and the potential case where it is neither the object you expect or a valid error).
Check HTTP Response Codes. If you receive a status code that isn't OK(200) then you shouldn't try to parse for a successful response. For instance you may check the code and handle response like this (the object types are not actual Java types, but are given to provide an example):
MyHttpResponse response = MyHttpHelper.execute(...);
int status = response.getMyStatusCode();
String responseData = response.getStringBody();
switch(status) {
case 200: {
//request is successful, parse valid data
break;
}
default: {
//request is not valid, parse error data
break;
}
}
Most importantly I want to get the exceptionMessage that I am able to view as part of the data returned when I use SoapUI to make the request. I don't see anything in HttpURLConnection that includes this detailed information. Only responseCode and responseMessage, which are nice, but are lacking the description I'm looking for.
Also, does SoapUI parse this raw data into JSON and XML itself, or is there a simple way I can get it as JSON through java as well?
Thanks
The server returns HTTP headers and in most cases a body. To get the body in case of a error, you have to do something like that:
InputStream is;
if (conn.getResponseCode() / 100 == 2) { // HTTP status code 2xx, e.g. 200
is = conn.getInputStream();
// read input stream -> this is the content you wanted
} else {
is = conn.getErrorStream();
// read input stream -> contains a description of the error
// depending on header "Content-Type" you can also parse the stream
// as JSON or XML or HTML ...
}
I recently moved over to Java and am attempting to write some REST tests against the netflix REST service.
I'm having an issue in that my response using rest assured either wants to send a gzip encoded response or "InputStream", neither of which provide the actual XML text in the content of the response. I discovered the "Accept-Encoding" header yet making that blank doesn't seem to be the solution. With .Net I never had to mess with this and I can't seem to find the proper means of returning a human readable response.
My code:
RestAssured.baseURI = "http://api-public.netflix.com";
RestAssured.port = 80;
Response myResponse = given().header("Accept-Encoding", "").given().auth().oauth(consumerKey, consumerSecret, accessToken, secretToken).param("term", "star wars").get("/catalog/titles/autocomplete");
My response object has a "content" value with nothing but references to buffers, wrapped streams etc. Trying to get a ToString() of the response doesn't work. None of the examples I've seen seem to work in my case.
Any suggestions on what I'm doing wrong here?
This has worked for me:
given().config(RestAssured.config().decoderConfig(DecoderConfig.decoderConfig().noContentDecoders())).get(url)
I guess in Java land everything is returned as an input stream. Using a stream reader grabbed me the data I needed.
Until its version 1.9.0, Rest-assured has been providing by default in the requests the header "Accept-Encoding:gzip,deflate" with no way of changing it.
See
https://code.google.com/p/rest-assured/issues/detail?id=154
It works for me:
String responseJson = get("/languages/").asString();