Trying to load a JSON file, getting an error but what does it mean?
public class MovieCollection{
private List<Movie> movies;
private Movie movie;
public MovieCollection() {
this.movies = new ArrayList<Movie>();
}
/**
* Creates a new book collection with the specified list of books pre-defined.
*
* #param books A books list.
*/
public MovieCollection(List<Movie> movies) {
this.movies= movies;
}
public static MovieCollection loadFromJSONFile (File file){
Gson gson = new Gson();
JsonReader jsonReader = null;
try {
jsonReader = new JsonReader(new FileReader(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("Error");
}
return gson.fromJson(jsonReader, MovieCollection.class);
}
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
The error clearly says that the text you are trying to read is actually an array and not a JSON. It is an Array of JSON. This means you need some way of reading an array of objects like the one shown below:
Gson gson = new Gson();
User[] userArray = gson.fromJson(userJson, User[].class);
This allows you to read array of User objects from a json array text. Sample json for above code is included below.
[
{
"name": "Alex",
"id": 1
},
{
"name": "Brian",
"id": 2
},
{
"name": "Charles",
"id": 3
}
]
User class is defined as
public class User
{
private long id;
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
Reference available at this link
Related
I am trying to parse array of json objects using gson library and I am unable to parse it because of json syntax exception. I am passing the json filepath as argument to method jsonparser.
heres the example code below that i have trouble parsing.
test.json - consists of array of objects
{
"EventRecords": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "2018-05-10T17:10:01.420Z",
"eventName": "ObjectCreated:Put"
}
]
}
GsonParser.java:
public class GsonParser {
public void jsonEncoder(String filePath)
{
Gson gson = new Gson();
Type listType = new TypeToken<List<Record>>(){}.getType();
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
List<Record> records = gson.fromJson(bufferedReader, listType);
System.out.println("\n\nEventRecords\n\n" + records.toString());
}
public static void main(String[] args) throws IOException {
GsonParser obj= new GsonParser();
File f = new File("/Users/test/Desktop/test.json");
obj.jsonEncoder(f.getAbsolutePath());
}
}
Record.java:
public class Record {
String eventVersion;
String eventSource;
String awsRegion;
String eventTime;
String eventName;
public String getEventVersion() {
return eventVersion;
}
public void setEventVersion(String eventVersion) {
this.eventVersion = eventVersion;
}
public String getEventSource() {
return eventSource;
}
public void setEventSource(String eventSource) {
this.eventSource = eventSource;
}
public String getAwsRegion() {
return awsRegion;
}
public void setAwsRegion(String awsRegion) {
this.awsRegion = awsRegion;
}
public String getEventTime() {
return eventTime;
}
public void setEventTime(String eventTime) {
this.eventTime = eventTime;
}
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
#Override
public String toString () {
return ToStringBuilder.reflectionToString(this,ToStringStyle.MULTI_LINE_STYLE);
}
}
Error:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
You have object in your JSON and EventRecord is array inside that object.
Add class say EventRecords
public class EventRecords{
private List<Record> eventRecords = new ArrayList<Record>();
public List<Record> getEventRecords() {
return this.eventRecords;
}
public void setEventRecords(List<Record> records) {
this.eventRecords= records;
}
}
And change your deserialization code as
EventRecords eventRecords = gson.fromJson(bufferedReader, listType);
And to fetch the ArrayList change
List<Record> records = eventRecords.getEventRecords();
i have an issue with the response of an API that i want to use, i was developing an APP that consumes this API using Retrofit 1.9.0 and GSON 2.3.1.
The Json that i want to parse is like:
{
"user1": {
"id": 1,
"name": "foo",
"address": "bar"
},
"user2":{
"id": 2,
"name": "foo",
"addres":"bar"
},
... it can be any number of users ...
"userN":{
"id": N,
"name": "foo,
"address": "bar"
}
}
So i have an POJO named User:
public class User{
private int id;
private String name;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
I was trying to parse that json with the configuration Map<String, User>:
Callback< <Map<String, User> > callback
But when i run it, i have a GSON error:
gson expecting array but found object
How can i parse the json in a correct way?
PD: i can't change the API response, it's an external API.
Try specifying a concrete type for you callback, like HashMap. Map is an interface.
Callback< <HashMap<String, User> > callback;
Usually you will get casting exception instead of a parsing error, but worth a try.
I am using the below code to receive Tweets from Twitter4j Search API in the form of JSON response. I am receiving the result in the form of List as specified in Twitter4j search API in the line
List<Status> tweets = result.getTweets();
The problem is that the tweets returned as List where one Status entry is having non-empty and non-null GeoLocation whereas another Status entry is having a null or empty GeoLocation. Since to retrieve the relevant fields from each Status entry (i.e. Tweet), I iterate over the List and call getters which is throwing me null for the Status entries where the GeoLocation field is null.
The approach I tried to follow:
I created a POJO TweetJSON_2 (defined at the bottom of the post) with the relevant fields and their getters and setters. I am using Jackson ObjectMapper to handle null values like below:
JsonGenerator generator = new JsonFactory().createGenerator(os);
generator.setPrettyPrinter(new DefaultPrettyPrinter());
TweetJSON_2 rawJSON;
ObjectMapper mapper = new ObjectMapper();
//mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
// ... rawJSON is populated ...
mapper.writeValue(generator, rawJSON);
However, when I am trying to get the geoLocation field from Status, using the below line which is marked with **
List<Status> tweets = result.getTweets();
I am getting the Java NullPointerException as follows:
[Mon Apr 20 11:32:47 IST 2015]{"statuses":[{"retweeted_status":{"contributors":null,"text":"<my text>",**"geo":null**,"retweeted":false,"in_reply_to_screen_name":null,"truncated":false,"lang":"en","entities":{"symbols":[],"urls":[],"hashtags": ... &include_entities=1","since_id_str":"0","completed_in":0.029}}
**Exception in thread "main" java.lang.NullPointerException
at analytics.search.twitter.SearchFieldsTweetsJSON_2.main(SearchFieldsTweetsJSON_2.java:78)**
For example: If I input a json String as
String s = "{\"first\": 123, \"second\": [{\"second_first\":null, \"second_second\":null}, {\"second_third\":null}, null], \"third\": 789, \"fourth\":null}";
The output should be like
"{\"first\": 123, \"third\": 789}";
What I want, is to replace all null elements from JSONArrays and all null key-value pairs from JSONObjects no matter at whatever level they are nested in my JSON response.
Object vs Tree Model Approach
I tried the Object Model parsing mechanism which is a javax.json.stream.JsonParser.Event based method but would need multiple times of access and object replacement on the JSON String depending on at what level the null is nested making this approach very complicated. At the same time if I use Tree Model mechanism, the entire JSON response would have to be stored as a Tree which may overflow my JVM heap memory because the JSON size can be pretty large based on my query parameters. I need to find a workable solution to overcome this problem. Any suggestions on solving the above discussed problem will be highly appreciated.
The code is as follows:
public class SearchFieldsTweetsJSON_2 {
/* Searches specific fields from Tweets in JSON format */
public static void main(String[] args) throws FileNotFoundException, IOException {
if (args.length < 2) {
System.out.println("java twitter4j.examples.search.SearchTweets [query][outputJSONFile]");
System.exit(-1);
}
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey("XXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthConsumerSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthAccessToken("NNNNNNNNN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthAccessTokenSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setJSONStoreEnabled(true);
Twitter twitter = new TwitterFactory(cb.build()).getInstance();
try {
Query query = new Query(args[0]);
QueryResult result;
File jsonFile = new File(args[1]);
System.out.println("File Path : " + jsonFile.getAbsolutePath());
OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(jsonFile));
JsonGenerator generator = new JsonFactory().createGenerator(os);
generator.setPrettyPrinter(new DefaultPrettyPrinter());
TweetJSON_2 rawJSON;
ObjectMapper mapper = new ObjectMapper();
//mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
do {
result = twitter.search(query);
List<Status> tweets = result.getTweets();
for (Status tweet : tweets) {
rawJSON = new TweetJSON_2();
rawJSON.setStatusId(Long.toString(tweet.getId()));
rawJSON.setUserId(Long.toString(tweet.getUser().getId()));
rawJSON.setUserName(tweet.getUser().getScreenName());
rawJSON.setStatusText(tweet.getText());
rawJSON.setGeoLocation(tweet.getGeoLocation().toString()); **<< Giving error at tweet.getGeoLocation() since GeoLocation is null**
mapper.writeValue(generator, rawJSON);
System.out.println(rawJSON.toString());
}
} while ((query = result.nextQuery()) != null);
generator.close();
System.out.println(os.toString());
} catch (TwitterException te) {
te.printStackTrace();
System.out.println("Failed to search tweets : " + te.getMessage());
System.exit(-1);
}
}
}
I have defined my TweetJSON_2 Java object as follows:
public class TweetJSON_2 {
public String statusId;
public String statusText;
public String userId;
public String userName;
public String geoLocation;
public String getStatusId() {
return statusId;
}
public void setStatusId(String statusId) {
this.statusId = statusId;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(String statusText) {
this.statusText = statusText;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGeoLocation() {
return geoLocation;
}
public void setGeoLocation(String geoLocation) {
this.geoLocation = geoLocation;
}
#Override
public String toString() {
return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
}
}
I have tried with reconfiguring my POJO in the below way and it successfully replaced all the nulls as specified in the setter methods. Didn't need to follow either Tree or Event-based model parsing of JSON string. HTH
The modified TweetJSON_2 POJO:
public class TweetJSON_2 {
public Long statusId = null;
public String statusText = null;
public Long userId = null;
public String userName = null;
public GeoLocation geoLocation = null;
public Long getStatusId() {
if (this.statusId==null)
return new Long(0L);
return statusId;
}
public void setStatusId(Long statusId) {
if (statusId==null)
this.statusId = new Long(0L);
else
this.statusId = statusId;
}
public String getStatusText() {
if (this.statusText==null)
return new String("");
return statusText;
}
public void setStatusText(String statusText) {
if (statusText==null)
this.statusText = new String("");
else
this.statusText = statusText;
}
public Long getUserId() {
if (this.userId==null)
return new Long(0L);
return userId;
}
public void setUserId(Long userId) {
if (userId==null)
this.userId = new Long(0L);
else
this.userId = userId;
}
public String getUserName() {
if (this.userName==null)
return new String("");
return userName;
}
public void setUserName(String userName) {
if (userName==null)
this.userName = new String("");
else
this.userName = userName;
}
public GeoLocation getGeoLocation() {
if (this.geoLocation==null)
return new GeoLocation(0.0,0.0);
return geoLocation;
}
public void setGeoLocation(GeoLocation geoLocation) {
if (geoLocation==null)
this.geoLocation = new GeoLocation(0.0,0.0);
else
this.geoLocation = geoLocation;
}
#Override
public String toString() {
return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
}
}
This is Json Object
[
{
"UserId":"demouser1",
"Catagories":[
{
"CatagoryName":"Entertainment",
"Persent":"25"
},
{
"CatagoryName":"Household",
"Persent":"25"
},
{
"CatagoryName":"Movie",
"Persent":"25"
},
{
"CatagoryName":"Misc",
"Persent":"25"
}
],
"RequestId":null,
"ResponseStatus":false,
"Token":null
}
]
Used The Following approach to parse the above Json
public class CategoryEntity {
private String CatagoryName;
private String Persent;
public String getCatagoryName() {
return CatagoryName;
}
public void setCatagoryName(String catagoryName) {
CatagoryName = catagoryName;
}
public String getPersent() {
return Persent;
}
public void setPersent(String persent) {
Persent = persent;
}
}
import java.util.List;
public class Entity {
private String UserId;
public String getUserId() {
return UserId;
}
public void setUserId(String userId) {
UserId = userId;
}
public List<CategoryEntity> getListCatagories() {
return ListCatagories;
}
public void setListCatagories(List<CategoryEntity> listPMMCatagories) {
ListCatagories = listPMMCatagories;
}
public String getRequestId() {
return RequestId;
}
public void setRequestId(String requestId) {
RequestId = requestId;
}
public boolean isResponseStatus() {
return ResponseStatus;
}
public void setResponseStatus(boolean responseStatus) {
ResponseStatus = responseStatus;
}
private List<CategoryEntity> ListCatagories;
private String RequestId;
private String Token;
public String getToken() {
return Token;
}
public void setToken(String token) {
Token = token;
}
private boolean ResponseStatus;
}
And
Following approach to convert the json object to corresponding object
Gson gson =new Gson();
JsonPrimitive listCatagoriesElement= element.getAsJsonPrimitive();
System.out.println("listCatagoriesElement.getAsString()>>"+listCatagoriesElement.getAsString());
sysout prints: listCatagoriesElement.getAsString()>>[{"UserId":"user1","ListCatagories":[{"CatagoryName":"Entertainment","Persent":"25"},{"CatagoryName":"Household","Persent":"25"},{"CatagoryName":"Movie","Persent":"25"},{"CatagoryName":"Misc","Persent":"25"}],"RequestId":null,"ResponseStatus":false,"Token":null}]
Entity entity = gson.fromJson(listCatagoriesElement, Entity.class);
Any ideas how should I fix it?
Thanks!
Your class CategoryEntity is correct, but in your class Entity, the attribute ListCatagories should be called Catagories to match the name in the JSON!
Apart from that, in order to parse the JSON you'd better do something like this:
Gson gson = new Gson();
Type listType = new TypeToken<List<Entity>>() {}.getType();
List<Entity> entities = gson.fromJson(yourJsonString, listType);
So you'll have a List containing just one Entity object, and you can access the values just with:
String catagoryNameI = entities.get(0).getCatagories().get(i).getCatagoryName();
String persentI = entities.get(0).getCatagories().get(i).getPersent();
You have to do this because your whole JSON response is an array, surrounded by [ ... ], so you need to parse it into some List...
I am using jackson to convert jason response to List of pojo. Below is the response which I am getting.
[
{
"code": "",
"total": 24,
"name": null
},
{
"code": "",
"total": 1,
"name": "Test"
}
]
And I am converting it to the List of Pojo. Below is my pojo.
public class ItemCategory {
private String code;
private String name;
private String total;
public ItemCategory() {
}
public ItemCategory(final String code, final String name, final String total) {
super();
this.code = code;
this.name = name;
this.total = total;
}
/**
* #return the code
*/
public String getCode() {
return code;
}
/**
* #param code
* the code to set
*/
public void setCode(final String code) {
this.code = code;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name
* the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* #return the count
*/
public String getTotal() {
return total;
}
/**
* #param count
* the count to set
*/
public void setTotal(final String total) {
this.total = total;
}
}
Everything works fine. But I want to remove the values to be converted to pojo which has code as blank/null value. i.e. "code": "", OR "code": null
I am using below jackson code to convert the json to pojo.
Object pojo = null;
try {
pojo = mapper.readValue(jsonString, typeReference);
} catch (JsonParseException e) {
throw new InvalidPojoException(e.toString(), e);
} catch (JsonMappingException e) {
throw new InvalidPojoException(e.toString(), e);
} catch (IOException e) {
throw new InvalidPojoException(e.toString(), e);
} catch (Exception e) {
throw new InvalidPojoException(e.toString(), e);
}
return pojo;
Using below code for json to object.
(List<ItemCategory>) JsonParserUtil.toPojo(serviceResponse.getStringResponse(),new TypeReference<List<ItemCategory>>(){});
Any pointer would be appreciated.
Thanks in advance.
You probably want to annotate your bean class like this:
#JsonSerialize(
include=JsonSerialize.Inclusion.NON_NULL,
)
source: JsonSerialize annotation javadoc