I have been trying to learn GSON, but I am struggling with it. I am trying to deserialize a JSON file into Java objects, using GSON. I have read a million other questions on here, and for the life of me, I can't understand what I'm doing wrong.
Here is my JSON text:
{
"movies": [
{
"name": "The Shawshank Redemption",
"url": "https://parsehub.com/sandbox/moviedetails?movie=The%20Shawshank%20Redemption",
"IMAX": "06:00 PM",
"rating": "9 . 2",
"cast": [
{
"character": "Andy Dufresne",
"actor": "Tim Robbins"
},
{
"character": "Ellis Boyd 'Red' Redding",
"actor": "Morgan Freeman"
},
{
"character": "Warden Norton",
"actor": "Bob Gunton"
},
{
"character": "Heywood",
"actor": "William Sadler"
}
]
},
{
"name": "Schindler's List",
"url": "https://parsehub.com/sandbox/moviedetails?movie=Schindler%27s%20List",
"IMAX": "06:15 PM",
"rating": "8 . 9",
"cast": [
{
"character": "Oskar Schindler",
"actor": "Liam Neeson"
},
{
"character": "Itzhak Stern",
"actor": "Ben Kingsley"
},
{
"character": "Amon Goeth",
"actor": "Ralph Fiennes"
}
]
}
]
}
And here is my Java code:
import com.google.gson.Gson;
import java.io.*;
import java.lang.reflect.Type;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
Gson gson = new Gson();
Movies[] movies = gson.fromJson(new FileReader("src/main/input.json"), (Type) Movies.class);
System.out.println(movies[0]);
}
class Movies {
String name;
String url;
String IMAX;
String rating;
ArrayList<Cast> cast;
}
class Cast {
ArrayList<CastMember> castMembers;
}
class CastMember{
String character;
String actor;
}
}
When I run this, I get the following error:
Exception in thread "main" java.lang.ClassCastException: class com.Main$Movies cannot be cast to class [Lcom.Main$Movies; (com.Main$Movies and [Lcom.Main$Movies; are in unnamed module of loader 'app')
at com.Main.main(Main.java:13)
The JSON you are deserializing represents an object with a list of objects on it. The Java object you are trying to deserialize to needs to match that.
First, create a new class MovieList.
class MovieList {
List<Movie> movies;
}
Update your Movies class to be called Movie, since it represents a single movie.
class Movie {
String name;
String url;
String IMAX;
String rating;
List<Cast> cast;
}
Now try calling gson.fromJson(...) with the following
MovieList movieList = gson.fromJson(new FileReader("src/main/input.json"), MovieList.class);
System.out.println(movieList.getMovies().get(0));
Try using this
Gson gson = new Gson();
Movies[] movies = gson.fromJson(new JsonReader(new FileReader("src/main/input.json"))),Movies[].class);
or something like
Type listType = new TypeToken<List<Movies>>() {}.getType();
List<Movies> movies = new Gson().fromJson(new JsonReader(new FileReader("src/main/input.json"))), listType);
Related
i'm trying to add new data to existing json file that named question.json but it's not working! it create a new file, can someone help me please!
mycode: i'm using json-simple1.1
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class Main {
public static void writeToJson() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("question", "q3");
ArrayList<String>anss = new ArrayList<>();
anss.add("a1");
anss.add("a2");
anss.add("a3");
anss.add("a4");
JSONArray arr = new JSONArray();
arr.add(anss.get(0));
arr.add(anss.get(1));
arr.add(anss.get(2));
arr.add(anss.get(3));
jsonObject.put("answers",arr);
jsonObject.put("correct_ans", "2");
jsonObject.put("level", "2");
jsonObject.put("team", "animal");
try {
FileWriter file = new FileWriter("json/quetion.json");
file.write(jsonObject.toJSONString());
file.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[]args) {
writeToJson();
}
}
{
"questions":[
{
"question": "q1",
"answers": [
"answer1",
"answer2",
"answer3",
"answer4"
],
"correct_ans": "2",
"level": "1",
"team": "animal"
},
{
"question": "q2",
"answers": [
"answer1",
"answer2",
"answer3",
"answer4"
],
"correct_ans": "1",
"level": "2",
"team": "animal"
}
]
}
this is the json file i want to add what i wrote in the code to this json file but i failed! i need someone to tell me how can i add a new json object like {"question" : "q2" ...} without changing the format of the json file or creating a new json file.
org.json.simple
The structure of your JSON has more levels of nesting than can be observed in your code therefore your result doesn't match.
That's what you have in the JSON:
JSONObject { field : JSONArray [ JSONObject { field : value, field : JSONArray, ... }
I.e. JSONObject which contains a JSONArray which might contain several JSONObjects which in turn contain a JSONArray.
That's how it can be translated into the code (to avoid redundancy logic which for creating a nested JSONObject was extracted into a separate method):
JSONObject root = new JSONObject();
JSONArray questions = new JSONArray();
JSONObject question1 = createQuestion(
"q1", "2", "1", "animal",
"answer1", "answer2", "answer3", "answer4"
);
JSONObject question2 = createQuestion(
"q2", "1", "2", "animal",
"answer1", "answer2", "answer3", "answer4"
);
Collections.addAll(questions, question1, question2);
root.put("questions", questions);
public static JSONObject createQuestion(String questionId,
String correctAnswer,
String level, String team,
String... answers) {
JSONObject question = new JSONObject();
question.put("question", questionId);
JSONArray answersArray = new JSONArray();
Collections.addAll(answersArray, answers);
question.put("answers", answersArray);
question.put("correct_ans", correctAnswer);
question.put("level", level);
question.put("team", team);
return question;
}
That's it.
There's a lot of low-level logic which you can eliminate if you would choose a more mature tool for parsing JSON like Jackson, Gson.
Jackson
Here's an example using Jackson library.
Firstly, let's create two POJO: one representing a single question and another wrapping a list of question. For convince, and also in order to avoid posting boilerplate code, I would use Lombock's.
Question class:
#Builder
#AllArgsConstructor
#Getter
public static class Question {
private String questionId;
private List<String> answers;
private String correctAnswer;
private String level;
private String team;
}
Questions class:
#AllArgsConstructor
#Getter
public static class Questions {
private List<Question> questions;
}
Here's how such objects can be serialized:
Question question3 = Question.builder()
.questionId("q1")
.answers(List.of("answer1", "answer2", "answer3", "answer4"))
.correctAnswer("2")
.level("1")
.team("animal")
.build();
Question question4 = Question.builder()
.questionId("q2")
.answers(List.of("answer1", "answer2", "answer3", "answer4"))
.correctAnswer("1")
.level("2")
.team("animal")
.build();
Questions questions1 = new Questions(List.of(question3, question4));
ObjectMapper mapper = new ObjectMapper();
String json1 = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(questions1);
System.out.println(json1);
Output:
{
"questions" : [ {
"questionId" : "q1",
"answers" : [ "answer1", "answer2", "answer3", "answer4" ],
"correctAnswer" : "2",
"level" : "1",
"team" : "animal"
}, {
"questionId" : "q2",
"answers" : [ "answer1", "answer2", "answer3", "answer4" ],
"correctAnswer" : "1",
"level" : "2",
"team" : "animal"
} ]
}
When trying to parse the json text file into an array list of Restaurant objects, I got the error "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path." I am confused where I got it wrong, as the data members in my Restaurant class correspond to the fields in the json file perfectly.
main
List<Restaurant> restaurants = new ArrayList<Restaurant>();
......
fr = new FileReader(filename);
br = new BufferedReader(fr);
Gson gson = new Gson();
TypeToken<List<Restaurant>> token = new TypeToken<List<Restaurant>>() {};
restaurants = gson.fromJson(br, token.getType());
Restaurant class
public class Restaurant {
public String name;
public String address;
public double latitude;
public double longitude;
public List<String> menu = new ArrayList<String>();
//public double distance;
public Restaurant(String name, String address, double latitude, double longitude, List<String> menu) {
this.name = name;
this.address = address;
this.latitude = latitude;
this.longitude = longitude;
this.menu = menu;
//this.distance = 0;
}
}
txt file
{
"data": [
{
"name": "Northern Cafe",
"address": "2904 S Figueroa Street",
"latitude": 34.025550,
"longitude": -118.277440,
"menu": [
"orange chicken",
"rice",
"noodles",
"dumplings"
]
},
{
"name": "The Lab Gastropub",
"address": "3500 S Figueroa Street",
"latitude": 34.019940,
"longitude": -118.280530,
"menu": [
"fried chicken",
"chicken sandwich",
"spinach dip",
"cheeseburger",
"fries",
"milkshake"
]
},
{
"name": "Taco Bell",
"address": "3629 S Vermont Ave",
"latitude": 34.022360,
"longitude": -118.291850,
"menu": [
"chicken taco",
"beef taco",
"fries",
"soda",
"cheese dipping sauce"
]
}
]
}
I think your problem is that you are missing the higher structure: this is confirmed by the fact that GSON is expecting a BEGIN_ARRAY, but got a BEGIN_OBJECT. The former is the [ token, and the later the { token.
{
"data": array
}
This means you should have a mapping:
class Data {
List<Restaurant> data;
}
And read it using:
TypeToken<Data> token = new TypeToken<Data>() {};
data = gson.fromJson(br, token.getType());
Or you should use the appropriate API (which I don't know, I don't use GSON) to get into the data node first, and then read its value as a List<Restaurant>.
Note that new TypeToken<Data>() {} is a construct probably made to capture a generic when using complex object such as List, Map, and that you may probably ignore with simple type:
data = gson.fromJson(br, Data.class);
You are trying to deserialise into an array of Restaurants but your file has an object, with one field data. Copying the list of restaurants to the outer level should solve your issue.
I am currently having trouble trying to parse this VCAP_SERVICES to java objects. I do not quite understand how to structure the POJO to allow it to map the values from the json string. Can someone please help me structure my pojo so that it is aligns with the json string?
I want to create objects for both of the credentials: accessToken... jdbcurl.
VCAP_SERVICES
"VCAP_SERVICES": {
"user-provided": [
{
"credentials": {
"accessTokenUri": "tokenurl",
"apiUrl": "apiurl",
"clientId": "typeofID",
"clientSecret": "secretAf",
"scope": "none"
},
"syslog_drain_url": "",
"volume_mounts": [],
"label": "user-provided",
"name": "OAuth2",
"tags": []
},
{
"credentials": {
"jdbcUrl": "jdbc:oracle:connection[host]:[port]/service",
"spring.datasource.driver-class-name": "oracle.jdbc.OracleDriver",
"spring.datasource.initialize": "false"
},
"syslog_drain_url": "",
"volume_mounts": [],
"label": "user-provided",
"name": "Database",
"tags": []
}
]
Java Class
ObjectMapper mapper = new ObjectMapper();
//json String to Object
CupsProperties properties = mapper.readValue(VCAP_Services, CupsProperties.class);
System.out.println(properties.getJdbcUrl() + "!!!!!!!!!!!!!!!!!!!");
POJOS
public class UserProviderWrapper {
#JsonProperty("user-provided")
public List<CupsProperties> cupsProperties;
#JsonProperty("syslog_drain_url")
public String syslog_drain_url;
#JsonProperty("volume_mounts")
public List<String> volume_mounts;
#JsonProperty("label")
public String label;
#JsonProperty("name")
public String name;
#JsonProperty("tags")
public List<String> tags;
//getters and setters
public class CupsProperties {
#JsonProperty("jdbcUrl")
public String jdbcUrl;
#JsonProperty("spring.datasource.driver-class-name")
public String driver;
#JsonProperty("spring.datasource.initialize")
public String initialize;
//getters and setters
Error
Unrecognized field "user-provided" (class rest.springframework.model.CupsProperties), not marked as ignorable (2 known properties: "jdbcUrl", "dataSource"])
at [Source: {"user-provided":[{ "credentials": { "jdbcUrl": "jdbc:oracle:thin:user/pass//host:port/service", "spring.datasource.driver-class-name": "oracle.jdbc.OracleDriver", "spring.datasource.initialize": "false" }, "syslog_drain_url": "", "volume_mounts": [ ], "label": "user-provided", "name": "Oracle", "tags": [ ] }]}; line: 1, column: 19] (through reference chain: rest.springframework.model.CupsProperties["user-provided"])
Check below solution and see if it fulfills your need. You can build on to it if you need to parse more fields.
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonParser {
public static void main(String[] args) {
String VCAP_Services = "{\"userProvided\": [{\"credentials\": {\"accessTokenUri\": \"tokenurl\",\"apiUrl\": \"apiurl\",\"clientId\": \"typeofID\",\"clientSecret\": \"secretAf\",\"scope\": \"none\"},\"syslog_drain_url\": \"\",\"volume_mounts\": [],\"label\": \"user-provided\",\"name\": \"OAuth2\",\"tags\": []},{\"credentials\": {\"jdbcUrl\": \"jdbc:oracle:connection[host]:[port]/service\",\"spring.datasource.driver-class-name\": \"oracle.jdbc.OracleDriver\",\"spring.datasource.initialize\": \"false\"},\"syslog_drain_url\": \"\",\"volume_mounts\": [],\"label\": \"user-provided\",\"name\": \"Database\",\"tags\": [] } ] } ";
CupsProperties properties=null;
try {
JSONParser jsonParser = new JSONParser();
JSONObject vcapServiceJSONObject = (JSONObject) jsonParser.parse(VCAP_Services);
for(Object key: vcapServiceJSONObject.keySet()){
String keyStr = (String) key;
JSONArray userProvidedList = (JSONArray) vcapServiceJSONObject.get(keyStr);
Iterator i = userProvidedList.iterator();
while (i.hasNext()) {
JSONObject innerObj = (JSONObject) i.next();
JSONObject credentialsObject = (JSONObject) innerObj.get("credentials");
if(credentialsObject.containsKey("jdbcUrl")){
//set to your pojo objects
System.out.println("JDBC url:" + credentialsObject.get("jdbcUrl"));
}
if(credentialsObject.containsKey("accessTokenUri")){
//set to your pojo objects
System.out.println("Access token URI:" + credentialsObject.get("accessTokenUri"));
}
}
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Output
Access token URI:tokenurl
JDBC url:jdbc:oracle:connection[host]:[port]/service
I am trying to convert a JSON array to a Java object, but I am having problems understanding how to use GSON.
The JSON array looks like this:
"[
{
"category": "1",
"checks": [
{
"check": "1.1",
"penaltypoints": "1.1",
"keypoint": "1.1"
},
{
"check": "1.2",
"penaltypoints": "1.2",
"keypoint": "1.2"
}
]
},
{
"category": "2",
"checks": [
{
"check": "2.1",
"penaltypoints": "2.1",
"keypoint": "2.1"
},
{
"check": "2.2",
"penaltypoints": "2.2",
"keypoint": "2.2"
}
]
}
]"
My corresponding Java classes are:
class Category {
public String description;
public List<Check> checks;
}
class Check {
public String description;
public float penaltyPoints;
public KeyPoint keypoint;
}
class KeyPoint {
public String description;
}
And this is how I called GSON:
Gson gson = new Gson();
Category categoriesArray[] = gson.fromJson(jsonString, Category[].class);
At the moment it is throwing up the following error:
Expected BEGIN_OBJECT but was STRING at line 1 column 125
I am new to GSON and am having problems understanding how it works. Can anyone please help me understand what I am doing wrong?
You're expecting this
"keypoint": "2.1"
to be mapped to
public KeyPoint keypoint;
...
class KeyPoint {
public String description;
}
In Java-JSON conversions, a POJO is meant to map to a JSON object and vice versa. Here, you're trying to map a JSON String to a POJO. That won't work by by default.
Either write and register your own TypeAdapter with Gson that will do this conversion or change your JSON to
"keypoint" : {
"description" : "2.1"
}
Can somebody help me with Gson parser. When I remove change from JSON and Result it works fine but with change it throws JsonParseException-Parse failed.
Result[] response = gson.fromJson(fileData.toString(), Result[].class);
I have classes like this
public class Result {
public String start_time;
public String end_time;
public change[] change;
}
and
public class change {
public String id;
public String name;
}
and Json string like
[
{
"start_time": "8:00",
"end_time": "10:00",
"change": [
{
"id": "1",
"name": "Sam"
},
{
"id": "2",
"name": "John"
}
]
},
{
"start_time": "9:00",
"end_time": "15:00",
"change": [
{
"id": "1",
"name": "Sam"
},
{
"id": "2",
"name": "John"
}
]
}
]
Can somebody tell me what I did wrong ? Any idea why it won't work with array ?
As has been suggested, you need to use a list instead. Gson has pretty good documentation for using parametized types with the parser, you can read more about it here. Your code will end up looking like this:
Type listType = new TypeToken<List<Result>>() {}.getType();
List<Result> results = gson.fromJson(reader, listType);
for (Result r : results) {
System.out.println(r);
}