I am coding in Java and I'm using the minimal-json library. I am trying to get some information from a json text (idk if it's an array).
I'm trying to access the "game" value inside "stream", but I always get a crash by nullpointer or a parseexception.
Here is the json string I'm trying to get (From the Twitch Api):
{"_links":{"self":"https://api.twitch.tv/kraken/streams/hackerc0w","channel":"https://api.twitch.tv/kraken/channels/hackerc0w"},"stream":{"_id":13817896816,"game":"Programming","viewers":13,"created_at":"2015-04-01T13:54:54Z","video_height":1080,"average_fps":59.9235368156,"_links":{"self":"https://api.twitch.tv/kraken/streams/hackerc0w"},"preview":{"small":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-80x45.jpg","medium":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-320x180.jpg","large":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-640x360.jpg","template":"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-{width}x{height}.jpg"},"channel":{"_links":{"self":"https://api.twitch.tv/kraken/channels/hackerc0w","follows":"https://api.twitch.tv/kraken/channels/hackerc0w/follows","commercial":"https://api.twitch.tv/kraken/channels/hackerc0w/commercial","stream_key":"https://api.twitch.tv/kraken/channels/hackerc0w/stream_key","chat":"https://api.twitch.tv/kraken/chat/hackerc0w","features":"https://api.twitch.tv/kraken/channels/hackerc0w/features","subscriptions":"https://api.twitch.tv/kraken/channels/hackerc0w/subscriptions","editors":"https://api.twitch.tv/kraken/channels/hackerc0w/editors","videos":"https://api.twitch.tv/kraken/channels/hackerc0w/videos","teams":"https://api.twitch.tv/kraken/channels/hackerc0w/teams"},"background":null,"banner":null,"broadcaster_language":"en","display_name":"hackerc0w","game":"Programming","logo":null,"mature":false,"status":"Coding a Chatbot in C","partner":false,"url":"http://www.twitch.tv/hackerc0w","video_banner":null,"_id":41236491,"name":"hackerc0w","created_at":"2013-03-11T17:08:22Z","updated_at":"2015-04-01T17:17:44Z","delay":0,"followers":28,"profile_banner":null,"profile_banner_background_color":null,"views":2948,"language":"de"}}}
The way I got if the livestreamer was live was like this:
public static boolean isStreamLive(String channel) {
try {
URL url = new URL(TWITCH_STREAM.replace("$c$", channel)) );
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ));
String inputLine = br.readLine();
br.close();
JsonObject jsonObj = JsonObject.readFrom(inputLine);
return ( jsonObj.get("stream").isNull() )?false:true;
} catch (IOException e) {
return false;
}
}
And I mostly tried to copy the method above. But I have been checking the documentation of the library to know and I have been trying a lot of things.
The last was this:
public static String checkGame(String channel) {
if (!isStreamLive(channel)) return "El Estreamer esta Offline!";
try {
URL url = new URL( insertChannel(TWITCH_STREAM, channel) );
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ));
String inputLine = br.readLine();
br.close();
JsonObject object = JsonObject.readFrom(inputLine);
JsonValue value = object.get("stream").asObject();
String msg = value.valueOf("status").toString();
return msg;
} catch (IOException e) {
return "Algo raro paso :/ error: 3";
}
return channel;
}
You've got two main problems with the code you've shown.
The first problem that you're having is that you're trying to get the status out of the wrong nested object. You're getting the stream object from the original json and then trying to get the value of the status key from that, but in the json you've posted status is part of a nested channel object.
The structure of the json object is like so:
{
"_links": { ... },
"stream": {
...
"channel":{
"_links": { ... },
...
"status":"Coding a Chatbot in C",
...
}
}
}
... so you can't get status directly from stream, you need to get channel from stream and get the status from that.
The second problem is that you're trying to use valueOf() to pull a value out of a JsonObject. valueOf() is a static method which creates a new object based on the supplied input, so it doesn't actually use data in the object you call it on.
Calling value.valueOf("status") will completely ignore data in value and create a new JsonObject containing the string "status".
If you want to get the value of a nested object, you need to drill down to it with a series of successive get("objName").asObject() calls, and then call .get("key") to obtain the value you want:
// hardcoded for example, actually would be read from BufferedReader
String inputLine = "{\"_links\":{\"self\":\"https://api.twitch.tv/kraken/streams/hackerc0w\",\"channel\":\"https://api.twitch.tv/kraken/channels/hackerc0w\"},\"stream\":{\"_id\":13817896816,\"game\":\"Programming\",\"viewers\":13,\"created_at\":\"2015-04-01T13:54:54Z\",\"video_height\":1080,\"average_fps\":59.9235368156,\"_links\":{\"self\":\"https://api.twitch.tv/kraken/streams/hackerc0w\"},\"preview\":{\"small\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-80x45.jpg\",\"medium\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-320x180.jpg\",\"large\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-640x360.jpg\",\"template\":\"http://static-cdn.jtvnw.net/previews-ttv/live_user_hackerc0w-{width}x{height}.jpg\"},\"channel\":{\"_links\":{\"self\":\"https://api.twitch.tv/kraken/channels/hackerc0w\",\"follows\":\"https://api.twitch.tv/kraken/channels/hackerc0w/follows\",\"commercial\":\"https://api.twitch.tv/kraken/channels/hackerc0w/commercial\",\"stream_key\":\"https://api.twitch.tv/kraken/channels/hackerc0w/stream_key\",\"chat\":\"https://api.twitch.tv/kraken/chat/hackerc0w\",\"features\":\"https://api.twitch.tv/kraken/channels/hackerc0w/features\",\"subscriptions\":\"https://api.twitch.tv/kraken/channels/hackerc0w/subscriptions\",\"editors\":\"https://api.twitch.tv/kraken/channels/hackerc0w/editors\",\"videos\":\"https://api.twitch.tv/kraken/channels/hackerc0w/videos\",\"teams\":\"https://api.twitch.tv/kraken/channels/hackerc0w/teams\"},\"background\":null,\"banner\":null,\"broadcaster_language\":\"en\",\"display_name\":\"hackerc0w\",\"game\":\"Programming\",\"logo\":null,\"mature\":false,\"status\":\"Coding a Chatbot in C\",\"partner\":false,\"url\":\"http://www.twitch.tv/hackerc0w\",\"video_banner\":null,\"_id\":41236491,\"name\":\"hackerc0w\",\"created_at\":\"2013-03-11T17:08:22Z\",\"updated_at\":\"2015-04-01T17:17:44Z\",\"delay\":0,\"followers\":28,\"profile_banner\":null,\"profile_banner_background_color\":null,\"views\":2948,\"language\":\"de\"}}}";
JsonObject object = JsonObject.readFrom(inputLine); // parse json into object
JsonObject stream = object.get("stream").asObject(); // get "stream" sub-object
JsonObject channel = stream.get("channel").asObject(); // get "channel" sub-object
JsonValue status = channel.get("status"); // get the value of "status"
String msg = status.asString();
System.out.println(msg); // Coding a Chatbot in C
Related
A client is sending me a JSON file through HTTP PUT, here is the file :
{
"nomPers": "Testworking",
"prenomPers": "WorkingTest",
"loginPers": "Work",
"pwdPers": "Ing",
"active": true
},
I'm using HTTPServlet as WebService framework and the org.json library to work with Json. I'm also using Tomcat Server. As Tomcat can't create a parameter map for this HTTP verb, i've to work with JSON objects.
So I did some searching and tries but still can't make it work, here is my code :
#Override
public void doPut(HttpServletRequest request, HttpServletResponse response) {
// this parses the incoming json to a json object.
JSONObject jObj = new JSONObject(request.getParameter("jsondata"));
Iterator<String> it = jObj.keys();
while(it.hasNext())
{
String key = it.next(); // get key
Object o = jObj.get(key); // get value
System.out.println(key + " : " + o); // print the key and value
}
So i'm parsing the incoming Json to a Json object to work with, then I create an Iterator to be able to loop through this object and get and and print datas for each key/value pair.
The problem is I get a NullPointerException error.
I guess it's because of the request.getParameter("jsondata"). It seems I don't get any parameters. I guess i've to create a string from the datas i get through the request to feed the JSONObject constructor, but i don't get how to achieve this.
I think the client send JSON data to you in the body of the request, not in a parameter. So the parameter that you try to parse as JSON data will be always null. To accomplish your task, you have first of all to get the body request and then parse it as JSON. For example, you can convert the body into a String with a method like this:
public static String getBody(HttpServletRequest request) {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
// throw ex;
return "";
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
}
}
}
body = stringBuilder.toString();
return body;
}
So, your method will become:
#Override
public void doPut(HttpServletRequest request, HttpServletResponse response) {
// this parses the incoming JSON from the body.
JSONObject jObj = new JSONObject(getBody(request));
Iterator<String> it = jObj.keys();
while(it.hasNext())
{
String key = it.next(); // get key
Object o = jObj.get(key); // get value
System.out.println(key + " : " + o); // print the key and value
}
...
So apparently your client was sending json string as request body due to which you were getting null while getting it from request.getParameter("jsondata").
In this case you need to pick request body data from request.getInputStream(), so your updated method should be something like this,
#Override
public void doPut(HttpServletRequest request, HttpServletResponse response) {
String jsonBody = new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(
Collectors.joining("\n"));
if (jsonBody == null || jsonBody.trim().length() == 0) {
// return error that jsonBody is empty
}
// this parses the incoming json to a json object.
JSONObject jObj = new JSONObject(jsonBody);
Iterator<String> it = jObj.keys();
while (it.hasNext()) {
String key = it.next(); // get key
Object o = jObj.get(key); // get value
System.out.println(key + " : " + o); // print the key and value
}
}
Hope this helps.
Use below parser and JsonObject to get the data in the form of JsonObject.
These classes are available in gson-2.8.5.jar, import this jar and then use the gson libray.
JsonParser parser = new JsonParser();
JsonObject o = parser.parse(request.getParameter("jsondata"));
You can get the keySet from the JsonObject and then iterator it using Iterator.
Hope this will help you!
I am using Java Eclipse to create an event management system which will write and read JSON files. Here I have code which creates a new JSON file...
public void actionPerformed(ActionEvent arg0) {
//Declaration of variables
String title = txtTitle.getText();
String month = (String) cboMonth.getSelectedItem();
String day = (String) cboDate.getSelectedItem();
String year = (String) cboYear.getSelectedItem();
String location = txtLocation.getText();
String description = txtDescription.getText();
String URL = txtURL.getText();
// Combine multiple variables together to make a single variable
String date = month + "" + day + "" + year;
// Create a new instance of the class called 'Event'
Event event = new Event();
// Assign values to the getter/setter methods of this instance
event.setName(title);
event.setDate(date);
event.setLocation(location);
event.setDesc(description);
event.setURL(URL);
// Add this new instance to the 'eventList' array list
MainMenu.eventList.add(event);
// Create a new instance of the class called 'Event'
JSONObject JSONEvent = new JSONObject();
// Add data to the JSON file
JSONEvent.put("Title", title);
JSONEvent.put("Date", date);
JSONEvent.put("Location", location);
JSONEvent.put("Description", description);
JSONEvent.put("URL", URL);
// Create a new JSON file called 'Events.json' that has elements added to it
try (FileWriter file = new FileWriter("Events.json", true)) {
file.write("\n");
file.write(JSONEvent.toJSONString());
file.flush();
// Error Handling
} catch (IOException e) {
e.printStackTrace();
}
}
This code works perfectly fine by creating a JSON file and populating it with JSONObjects. Here is an image of what a single entry in the JSON file looks like... Single JSON Element
I then have a separate class with the following code which attempts to read the JSON file and output its contents to the console...
public static void main(String[] args) {
JSONObject JSONEvent;
String line = null;
try {
FileReader fileReader = new FileReader("Events.json");
BufferedReader bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
JSONEvent = (JSONObject) new JSONParser().parse(line);
String title = (String) JSONEvent.get("Title");
System.out.println(title);
String date = (String) JSONEvent.get("Date");
System.out.println(date);
String location = (String) JSONEvent.get("Location");
System.out.println(location);
String description = (String) JSONEvent.get("Description");
System.out.println(description);
String URL = (String) JSONEvent.get("URL");
System.out.println(URL);
Event event = new Event();
event.setName(title);
event.setDate(date);
event.setLocation(location);
event.setDesc(description);
event.setURL(URL);
MainMenu.eventList.add(event);
}
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
When I run this code, I get the following errors in the console...
Unexpected token END OF FILE at position 0
Does anyone have any idea what this error means?
The very first thing you write to the file is an empty line:
file.write("\n");
So, when reading the file, you're trying to parse an empty string to JSON, hence the exception: the parser finds the end of its input before even having a chance to parse anything.
Instead of relying on the internal format of the generated JSON, and to write several distinct JSON objects to the file, it would be simpler, and safer, to write a single array of objects all at once in the file (replacing its previous content), and to read the whole array at once in memory.
Faced a similar issue. Was trying to write a JSON data record from a file on a Kafka topic. Was getting Unexpected token END OF FILE at position . As a fix, I cleared all the \n characters from the file and tried sending it to the kafka topic. It worked.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I'm learning java recently and when I wanted to parse the data from a weather website, I got this error and I still can't figure it out, can anybody tell why I got this error: java.lang.NullPointerException ?
public class main {
public static void main(String []args) {
try {
URL url = new URL("http://api.worldweatheronline.com/premium/v1/past-weather.ashx?key=caa2f68a7b2b43a09c115021171404&format=json&q=atlanta&date=2015-07-20&tp=24");
InputStream is = url.openStream();
JsonReader rdr = Json.createReader(is);
JsonObject obj = rdr.readObject();
JsonArray data = obj.getJsonArray("weather");
JsonObject objectOfData = data.getJsonObject(0);
System.out.println(objectOfData.getString("date"));
} catch (Exception ex){
System.out.println(ex);
}
}
}
Here is the data parsed from Postman:
Here is the trace log:
Here is the picture of line 19
You may print the stack trace in the catch method, and find on which line there is error and act accordingly.
Part 1: Error with Callback
I checked your URL in my browser and it appears you have the callback parameter set to wrap the json with a request callback which looks like this:
request({"data": .... })
The parser is getting hung up on the first character which it doesn't recognize as proper json.
Try this URL instead:
http://api.worldweatheronline.com/premium/v1/past-weather.ashx?key=caa2f68a7b2b43a09c115021171404&format=json&q=atlanta&date=2015-07-20&tp=24
Part 2: Null Pointer Exception
The json is being parsed out of order. You needed to create an object from the root element "data" before accessing the array.
try {
URL url = new URL("http://api.worldweatheronline.com/premium/v1/past-weather.ashx?key=caa2f68a7b2b43a09c115021171404&format=json&q=atlanta&date=2015-07-20&tp=24");
InputStream is = url.openStream();
JsonReader rdr = Json.createReader(is);
JsonObject obj = rdr.readObject();
JsonObject objectOfData = (JsonObject) obj.get("data");
JsonArray data = objectOfData.getJsonArray("weather");
JsonObject a = data.getJsonObject(0);
System.out.println(a.getString("date"));
} catch (Exception ex){
System.out.println(ex);
}
Apologies for the long code post but am wondering if someone can help with a multithreading question (I am quite new to multi-threading). I am trying to design a facade class to a RESTFUL web services API that can be shared with multiple threads. I am using HttpURLConnection to do the connection and Google GSON to convert to and from JSON data.
The below class is what I have so far. In this example it has one public method to make an API call (authenticateCustomer()) and the private methods are used to facilitate the API call (i.e to build the POST data string, make a POST request etc).
I make one instance of this class and share it with 1000 threads. The threads call the authenticateCustomer() method. Most of the threads work but there is some threads that get a null pointer exception which is because I haven't implemented any synchronization. If I make the authenticateCustomer() method 'synchronized' it works. The problem is this results in poor concurrency (say, for example, the POST request suddenly takes a long time to complete, this will then hold up all the other threads).
Now to my question. Is the below class not stateless and therefore thread-safe? The very few fields that are in the class are declared final and assigned in the constructor. All of the methods use local variables. The Gson object is stateless (according to their web site) and created as a local variable in the API method anyway.
public final class QuizSyncAPIFacade
{
// API Connection Details
private final String m_apiDomain;
private final String m_apiContentType;
private final int m_bufferSize;
// Constructors
public QuizSyncAPIFacade()
{
m_apiDomain = "http://*****************************";
m_apiContentType = ".json";
m_bufferSize = 8192; // 8k
}
private String readInputStream(InputStream stream) throws IOException
{
// Create a buffer for the input stream
byte[] buffer = new byte[m_bufferSize];
int readCount;
StringBuilder builder = new StringBuilder();
while ((readCount = stream.read(buffer)) > -1) {
builder.append(new String(buffer, 0, readCount));
}
return builder.toString();
}
private String buildPostData(HashMap<String,String> postData) throws UnsupportedEncodingException
{
String data = "";
for (Map.Entry<String,String> entry : postData.entrySet())
{
data += (URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8") + "&");
}
// Trim the last character (a trailing ampersand)
int length = data.length();
if (length > 0) {
data = data.substring(0, (length - 1));
}
return data;
}
private String buildJSONError(String message, String name, String at)
{
String error = "{\"errors\":[{\"message\":\"" + message + "\",\"name\":\"" + name + "\",\"at\":\"" + at + "\"}]}";
return error;
}
private String callPost(String url, HashMap<String,String> postData) throws IOException
{
// Set up the URL for the API call
URL apiUrl = new URL(url);
// Build the post data
String data = buildPostData(postData);
// Call the API action
HttpURLConnection conn;
try {
conn = (HttpURLConnection)apiUrl.openConnection();
} catch (IOException e) {
throw new IOException(buildJSONError("Failed to open a connection.", "CONNECTION_FAILURE", ""));
}
// Set connection parameters for posting data
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
// Write post data
try {
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(data);
wr.flush();
wr.close();
} catch (IOException e) {
throw new IOException(buildJSONError("Failed to post data in output stream (Connection OK?).", "POST_DATA_FAILURE", ""));
}
// Read the response from the server
InputStream is;
try {
is = conn.getInputStream();
} catch (IOException e) {
InputStream errStr = conn.getErrorStream();
if (errStr != null)
{
String errResponse = readInputStream(errStr);
throw new IOException(errResponse);
}
else
{
throw new IOException(buildJSONError("Failed to read error stream (Connection OK?).", "ERROR_STREAM_FAILURE", ""));
}
}
// Read and return response from the server
return readInputStream(is);
}
/* -------------------------------------
*
* Synchronous API calls
*
------------------------------------- */
public APIResponse<CustomerAuthentication> authenticateCustomer(HashMap<String,String> postData)
{
// Set the URL for this API call
String apiURL = m_apiDomain + "/customer/authenticate" + m_apiContentType;
Gson jsonConv = new Gson();
String apiResponse = "";
try
{
// Call the API action
apiResponse = callPost(apiURL, postData);
// Convert JSON response to the required object type
CustomerAuthentication customerAuth = jsonConv.fromJson(apiResponse, CustomerAuthentication.class);
// Build and return the API response object
APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(true, customerAuth, null);
return result;
}
catch (IOException e)
{
// Build and return the API response object for a failure with error list
APIErrorList errorList = jsonConv.fromJson(e.getMessage(), APIErrorList.class);
APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(false, null, errorList);
return result;
}
}
}
If you are getting an error it could be because you are overloading the authentication service (something which doesn't happen if you do this one at a time) Perhaps it returning a error like 500, 503 or 504 which you could be ignoring and getting nothing you expect back, you return null http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
I would use less threads assuming you don't have 1000 cpus, its possible having this many threads will be slower rather than more efficeint.
I would also check that your service is returning correctly every time and investigate why you get a null value.
If your service can only handle say 20 requests at once, you can try using a Semaphore as a last resort. This can be using to limit the numebr of concurrent requests.
Any stateless class is inherently threadsafe, provided that the objects it accesses are either private to the thread, or threadsafe themselves.
All sample function I've seen so far avoid, for some reason, returning a string. I am a total rookie as far as Java goes, so I am not sure whether this is intentional. I know that in C++ for example, returning a reference to a string is way more efficient than returning a copy of that string.
How does this work in Java?
I am particularly interested in Java for Android, in which resources are more limited than desktop/server environment.
To help this question be more focused, I am providing a code snippet in which I am interested in returning (to the caller) the string page:
public class TestHttpGet {
private static final String TAG = "TestHttpGet";
public void executeHttpGet() throws Exception {
BufferedReader in = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI("http://www.google.com/"));
HttpResponse response = client.execute(request); // actual HTTP request
// read entire response into a string object
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
String page = sb.toString();
Log.v(TAG, page); // instead of System.out.println(page);
}
// a 'finally' clause will always be executed, no matter how the program leaves the try clause
// (whether by falling through the bottom, executing a return, break, or continue, or throwing an exception).
finally {
if (in != null) {
try {
in.close(); // BufferedReader must be closed, also closes underlying HTTP connection
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
In the example above, can I just define:
public String executeHttpGet() throws Exception {
instead of:
public void executeHttpGet() throws Exception {
and return:
return (page); // Log.v(TAG, page);
A String in java corresponds more or less to std::string const * in c++. So, it's cheap to pass around, and can't be modified after it's created (String is immutable).
String is a reference type - so when you return a string, you're really just returning a reference. It's dirt cheap. It's not copying the contents of the string.
In java most of the time you return something, you return it by reference. There's no object copying or cloning of any kind. So it is fast.
Also, Strings in Java are immutable. No need to worry about that either.