i'm trying to retrieve text from wikipedia to use on an Android app. I'm using Java.
The first thing I want to do is to retrieve the sections from an specific article, show them to the user and, when the user clicks on one section, get the section text with another http request.
So, the two requests are these:
http://en.wikipedia.org/w/api.php?format=json&action=parse&page=Valencia_Cathedral&prop=sections
and then this one:
http://en.wikipedia.org/w/api.php?format=json&action=parse&page=Valencia_Cathedral&prop=text§ion=1
My question is: What kind of java objects should I create to store the information and then convert it to these classes using .fromJSON()?
Thanks to #NathanZ, I created these two classes:
public class WikiResponseSections {
String title;
List<Section> sections;
}
public class Section {
int toclevel;
String level;
String line;
String number;
String index;
String fromtitle;
int byteoffset;
String anchor;
}
But, when I convert the HTTP response to these objets by Gson, and try to read the value of the field 'title' there's an error that triggers: JavaNullPointerException.
Here's my code for the conversion:
InputStream stream = null;
try {
stream = entity.getContent();
} catch (IllegalStateException e) {
Log.e("Stream","ERROR illegalstateexception");
} catch (IOException e) {
Log.e("Stream","ERROR exception");
}
reader = new BufferedReader(new InputStreamReader(stream));
GsonBuilder bldr = new GsonBuilder();
Gson gson = bldr.create();
WikiResponse = gson.fromJson(reader, WikiResponseSections.class);
if (WikiResponse != null){
Log.i("WikiResponse",WikiResponse.getTitle()); //The error triggers HERE
publishProgress();
}
else
Log.i("WikiResponse","NULL");
}
Thanks for your help again
You can use the Google's Gson library.
It works like this:
InputStream source = ...; // your code to get the Json from a url
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
MyResponse response = gson.fromJson(reader, MyResponse.class);
Where MyResponse is your object. When you create MyResponse, give your fields the same name and type as the Json's fields
MyResponse class can be as follows:
public class MyResponse{
String title;
ArrayList<sections>;
}
public class sections{
int toclevel;
String level;
String line;
String number;
String fromtitle;
long byteoffset;
String anchor;
}
public class WikiResponseParse{
Parse parse;
public class Parse{
String title, text;
}
}
If you can't use the json fields name because it's not Java compliant:
Add the following import:
import com.google.gson.annotations.SerializedName;
and in your class:
#SerializedName("*")
public String star;
Related
Here is the entire class:
public class Item {
static class Page {
Map <String,String> other_data;
Map <String,Map<String,List<Map<String,String>>>> specification;
}
public static String showName() throws Exception {
String json = Json.fetch(jsonurl);
Gson gson = new Gson();
Page result = gson.fromJson(json, Page.class);
return result.specification.get("result").get("feature").get(0).get("value");
// not working.
//return result.other_data.get("id"); <-- this one working
}
}
Here's how I fetch the json:
public class Json {
public static String fetch(String urlString) throws Exception {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(Connection.auth(urlString)));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
//return buffer.toString();
return buffer.toString();
} finally {
if (reader != null)
reader.close();
}
}
}
I have been struggling to get a specific value from a mixed-type JSON feed using gson.
{
"other_data":{"id":"150","name":"AA"},
"specification":{"result":{"feature":[{"name":"attribute A","value":"50"}]}}
}
The feed should be valid since I can get 150 from other_data
`return result.other_data.get("id");`
However I can't get the value 50 from the first object of the array feature:
return result.specification.get("result").get("feature").get(0).get("value");
I'm receiving this error:
Expected BEGIN_OBJECT but was STRING at line 1 column 37948 path $.specification.
I think the declaration Map <String,Map<String,List<Map<String,String>>>> specification; is incorrect. I did a little debugging by changing it to Map <String,Object> specification. I managed to get the stringified object
{"feature":[{"name":"attribute A","value":"50"}]}
public class Item {
static class Page {
String page_type;
String name;
Map <String,String> submit_user_data;
Map <String,Object> specification;
}
public static String showName() throws Exception {
String json = Json.fetch(jsonurl);
Gson gson = new Gson();
Page td = gson.fromJson(json, Page.class);
return td.specification.get("result").toString(); // this one works!
}
}
Would anyone tell me what's wrong with the class getting the error?
Apparently escaping the json string solves the issue:
public static void main(String args[]) {
String json = "{\"other_data\":{\"id\":\"150\",\"name\":\"AA\"},\"specification\":{\"result\":{\"feature\":[{\"name\":\"attribute A\",\"value\":\"50\"}]}}}";
Gson gson = new Gson();
Page result = gson.fromJson(json, Page.class);
System.out.println(result.specification.get("result").get("feature").get(0).get("value"));
}
So I already succeed with one Json to get it all worked. Now I have another class where I want to get only one attribute. I have now a moviedatabase class (which work with JSON and gets all the information) and now I want to add a Trailer which is from Youtube API. so basically I need it to be added into the same JSON to make it easier for me in the future to get it into a HTML. the only problem is I cant get it work. I get a syntax error JSON when using this method.
EDIT CODE 1.1:
Youtube attribute:
public class FilmAttribut {
private String title = "";
private String release = "";
private int vote = 0;
private String overview = "";
private String poster = "";
private String trailer = "";
// getters + setters stripped
}
Youtube class:
public class Youtube {
FilmAttribut movie = new FilmAttribut();
public void search(String trailer, FilmAttribut in) {
HttpResponse<JsonNode> response;
try {
response = Unirest.get("https://www.googleapis.com/youtube/v3/search?key=[app key here]&part=snippet")
.queryString("q", trailer + " trailer")
.asJson();
JsonNode json = response.getBody();
JSONObject envelope = json.getObject();
JSONArray items = envelope.getJSONArray("items");
in.setTrailer("https://youtu.be/" + items.getJSONObject(0).getJSONObject("id").getString("videoId")); //Gives me error here
}
catch (JSONException e) {
e.printStackTrace();
} catch (UnirestException e) {
e.printStackTrace();
}
return null;
}
}
and main method
public class WebService {
public static void main(String[] args) {
setPort(1337);
Gson gson = new Gson();
Youtube yt = new Youtube();
MovieDataBase mdb = new MovieDataBase();
get("/search/:movie", (req, res) -> {
String titel = req.params(":movie");
FilmAttribut film = mdb.searchMovie(titel);
yt.search(titel, film);
String json = gson.toJson(film);
return json;
});
So I think the problem is that you can't have two gson.toJson(film) + gson.toJson(trailer); Because it makes the JSON twice, where one time is for the film (aka. movie) and then a new json is created with trailer which make the syntax error.
So my real question is, is it possible to have another class like I have now youtube. to send the information to a attribute class where I have all my attributes and then run it in main-method so that I can get all the JSON in one JSON.
If I did understand well what you are asking, yes you can, but I would do something like that instead:
public void search(String trailer, FileAttribut in) {
// fetch the trailer from youtube (NB: you should use getters/setters, not public fields)
in.setTrailer("https://youtu.be/" + items.getJSONObject(0).getJSONObject("id").getString("videoId"));
}
and:
FilmAttribut film = mdb.searchMovie(titel);
yt.search(titel, film); // pass "film" to "fill" its trailer
return gson.toJson(film);
OR
public String search(String trailer) {
// fetch the trailer from youtube
return "https://youtu.be/" + items.getJSONObject(0).getJSONObject("id").getString("videoId");
}
and:
FilmAttribut film = mdb.searchMovie(titel);
film.setTrailer(yt.search(titel));
return gson.toJson(film);
I am trying to convert java object to json. I have a java class which reads a specific column from a text file. And I want to store that read column in json format.
Here is my code. I dont know where I am going wrong.
Thanks in advance.
File.java
public class File {
public File(String filename)
throws IOException {
filename = readWordsFromFile("c:/cbir-2/sample/aol.txt");
}
public String value2;
public String readWordsFromFile(String filename)
throws IOException {
filename = "c:/cbir-2/sample/aol.txt";
// Creating a buffered reader to read the file
BufferedReader bReader = new BufferedReader(new FileReader(filename));
String line;
//Looping the read block until all lines in the file are read.
while ((line = bReader.readLine()) != null) {
// Splitting the content of tabbed separated line
String datavalue[] = line.split("\t");
value2 = datavalue[1];
// System.out.println(value2);
}
bReader.close();
return "File [ list=" + value2 + "]";
}
}
GsonExample.java
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args)
throws IOException {
File obj = new File("c:/cbir-2/sample/aol.txt");
Gson gson = new Gson();
// convert java object to JSON format,
// and returned as JSON formatted string
String json = gson.toJson(obj);
try {
//write converted json data to a file named "file.json"
FileWriter writer = new FileWriter("c:/file.json");
writer.write(json);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(json);
}
}
I recommend you to use
Jackson
High-performance JSON processor.
from http://jackson.codehaus.org/
here is the sample from their tutorial
The most common usage is to take piece of JSON, and construct a Plain Old Java Object ("POJO") out of it. So let's start there. With simple 2-property POJO like this:
// Note: can use getters/setters as well; here we just use public fields directly:
public class MyValue {
public String name;
public int age;
// NOTE: if using getters/setters, can keep fields `protected` or `private`
}
we will need a com.fasterxml.jackson.databind.ObjectMapper instance, used for all data-binding, so let's construct one:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
The default instance is fine for our use -- we will learn later on how to configure mapper instance if necessary. Usage is simple:
MyValue value = mapper.readValue(new File("data.json"), MyValue.class);
// or:
value = mapper.readValue(new URL("http://some.com/api/entry.json"), MyValue.class);
// or:
value = mapper.readValue("{\"name\":\"Bob\", \"age\":13}", MyValue.class);
And if we want to write JSON, we do the reverse:
mapper.writeValue(new File("result.json"), myResultObject);
// or:
byte[] jsonBytes = mapper.writeValueAsBytes(myResultObject);
// or:
String jsonString = mapper.writeValueAsString(myResultObject);
Processing a file that have the information in columns like a csv I recomend for this task use opencsv here is an example for information in 5 columns separated by '|'
import com.opencsv.CSVReader;
import pagos.vo.UserTransfer;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* Created by anquegi on
*/
public class CSVProcessor {
public List<String[]> csvdata = new ArrayList<String[]>();
public CSVProcessor(File CSVfile) {
CSVReader reader = null;
try {
reader = new CSVReader(new FileReader(CSVfile),'|');
} catch (FileNotFoundException e) {
e.printStackTrace();
Logger.error("Cannot read CSV: FileNotFoundException");
}
String[] nextLine;
if (reader != null) {
try {
while ((nextLine = reader.readNext()) != null) {
this.csvdata.add(nextLine);
}
} catch (IOException e) {
e.printStackTrace();
Logger.error("Cannot read CSV: IOException");
}
}
}
public List<TransfersResult> extractTransfers() {
List<TransfersResult> transfersResults = new ArrayList<>();
for(String [] csvline: this.csvdata ){
if(csvline.length >= 5){
TransfersResult transfersResult = new TransfersResult(csvline[0]
,csvline[1],csvline[2],csvline[3],csvline[4]);
// here transfersResult is a pojo java object
}
}
return transfersResults;
}
}
and for returning a json from a servlet this is solved in this question in stackoverflow
How do you return a JSON object from a Java Servlet
Looks like you might be overwriting value2 for each line.
value2= datavalue[1];
EDIT: Can you make value2 a List and add to it.
value2.add(datavalue[1]);
EDIT2: You need to check the size of the array before using it.
if (datavalue.length >= 2){
value2.add(datavalue[1]);
}
The reason for the exception could be
value2=datavlue[1];
means during your first execution of while loop , you are trying to assign seconds element(datavalue[1]) in the String array to value2 , which is not created by then.So its giving that exception.
Suppose I am fetching from an api some json array as so
[{"id":1,"title":"title","description":"description","vote":null,"created_at":"2013-11-12T21:08:10.922Z","updated_at":"2013-11-12T21:08:10.922Z"}]
I want to retrieve this json as an Some object from URL_Some url
public class Some implements Serializable {
private String id;
private String title;
private String description;
private String vote;
private String created_at;
private String updated_at;
}//with all getters and setters
.
public List<Some> getSome() throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_Some));
SomeWrapper response = fromJson(request, SomeWrapper.class);
Field[] fields = response.getClass().getDeclaredFields();
for (int i=0; i<fields.length; i++)
{
try {
Log.i("TAG", (String) fields[i].get(response));
} catch (IllegalAccessException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
Log.i("TAG", fields[i].getName());
}
if (response != null && response.results != null)
return response.results;
return Collections.emptyList();
} catch (HttpRequestException e) {
throw e.getCause();
}
}
and SomeWrapper is simply
private static class SomeWrapper {
private List<Some> results;
}
The problem is that I keep on getting this message
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY
PS : I use
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
Your json should actually be like this:
{"results": [{"id":1,"title":"title","description":"description","vote":null,"created_at":"2013-11-12T21:08:10.922Z","updated_at":"2013-11-12T21:08:10.922Z"}]}
Gson will try to parse the json and create a SomeWrapper object. This alone tells Gson he will wait for a json with this format {...} since he's expecting an object. However you passed an array instead, that's why it complains about expecting BEGIN_OBJECT ({) but getting BEGIN_ARRAY instead ([). After that, it will expect this json object to have a results field, which will hold an array of objects.
You can create List<Some> directly without the need of a wrapper class however. To do so do this instead:
Type type= new TypeToken<List<Some>>() {}.getType();
List<Some> someList = new GsonBuilder().create().fromJson(jsonArray, type);
In this case, you can use the original json array you posted.
The JSON you posted is a JSON array, which is indicated by the squared brackets around it: [ ].
You'd have to read the first object from the JSON array.
I personally use the org.json packages for Android JSON and parse my JSON in a manner like this:
private void parseJSON(String jsonString) {
JSONArray json;
try {
json = new JSONArray(jsonString);
JSONObject jsonObject = jsonArray.getJSONObject(0);
String id = jsonObject.getString("id");
} catch (JSONException jsonex) {
jsonex.printStackTrace();
}
}
If you've got multiple JSON objects in your array you can iterate over them by using a simple for loop (not for each!)
I'm having trouble trying to deserialize a JSON string. I'm using gson
This is the class
public class Notebook {
public static String DESCRIPTION = "description";
#SerializedName("id") private long id;
#SerializedName("user_id") private long userId;
#SerializedName("description") private String description;
#SerializedName("created_at") private String railsCreated;
#SerializedName("updated_at") private String railsUpdated;
#SerializedName("created_android") private String androidCreated;
#SerializedName("updated_android") private String androidUpdated;
private List<Note> notes;
private boolean isUploaded = false;
/*constructors, getters, and setters */
public static void uploadNotebook(Notebook notebook) {
MultipartEntity entity = new MultipartEntity();
HttpResponse response;
Notebook updatedNotebook = new Notebook();
Gson gson = new Gson();
try {
StringBody description = new StringBody(notebook.getDescription());
StringBody user = new StringBody("1");
StringBody format = new StringBody("json");
// StringBody androidCreated = new StringBody(notebook.getAndroidCreated().toString());
// StringBody androidUpdated = new StringBody(notebook.getAndroidUpdated().toString());
entity.addPart("description", description);
entity.addPart("user_id", user);
entity.addPart("format", format);
// entity.addPart("android_created", androidCreated);
// entity.addPart("android_updated", androidUpdated);
response = WebService.postRequest(entity, WebService.POST_NOTEBOOK_URL);
String json = EntityUtils.toString(response.getEntity());
Log.i("Note Uploader", json);
updatedNotebook = gson.fromJson(json, Notebook.class);
if(updatedNotebook != null) {
Log.i("Notebook ID", ""+updatedNotebook.getId());
Log.i("Notebook userID", ""+updatedNotebook.getUserId());
Log.i("Notebook Title", ""+updatedNotebook.getDescription());
Log.i("Notebook CreatedAt", ""+updatedNotebook.getRailsCreated());
Log.i("Notebook UpdatedAt", ""+updatedNotebook.getRailsUpdated());
updatedNotebook.setUploaded(true);
}
} catch (UnsupportedEncodingException e) {
Log.i("Note Uploader", e.getMessage());
} catch (ClientProtocolException e) {
Log.i("Note Uploader", e.getMessage());
} catch (IOException e) {
Log.i("Note Uploader", e.getMessage());
}
}
}
Rails replies with the following json object when I issue a post:
{
"notebook":{
"created_android":null,
"created_at":"2011-12-30T06:35:42Z",
"description":"Tatata",
"id":12,
"updated_android":null,
"updated_at":"2011-12-30T06:35:42Z",
"user_id":1
}
}
But this is what I get when I try to print updatedNotebook fields.
12-30 14:35:42.673: INFO/Notebook ID(551): 0
12-30 14:35:42.673: INFO/Notebook userID(551): 0
12-30 14:35:42.673: INFO/Notebook Title(551): null
12-30 14:35:42.673: INFO/Notebook CreatedAt(551): null
12-30 14:35:42.673: INFO/Notebook UpdatedAt(551): null
I'm probably missing something...
Your class doesn't match the JSON.
Your JSON is an object that contains one field ("notebook") which has an object as its value that contains the fields you're actually looking for.
The JSON would need to look like:
{
"created_android":null,
"created_at":"2011-12-30T06:35:42Z",
"description":"Tatata",
"id":12,
"updated_android":null,
"updated_at":"2011-12-30T06:35:42Z",
"user_id":1
}
To map correctly to your object. You also have mismatched field names that need to be corrected. Looks like you got those.
Edit: To clarify, the JSON you have now would currently map to this:
public class NotebookContainer
{
public Notebook notebook;
}
I notice that several of your serialized names do not match the json. android_created and android_updated should have the updated first to match the json. There may be other problems here but that stands out as an issue.
Another approach: If you have control over the Rails dump, you can ignore the root element using ActiveRecord::Base.include_root_in_json = false before your start generating json via to_json