Deserialize a complex JSON Object into a POJO using GSON - java

I'm getting the following JSON response from IMDB.
{
"Search":
[
{
"Title":"Seven Pounds",
"Year":"2008",
"imdbID":"tt0814314",
"Type":"movie",
"Poster":"someUrl"
},
{
"Title":"Seven Samurai",
"Year":"1954",
"imdbID":"tt0047478",
"Type":"movie",
"Poster":"someUrl"
}
],
"totalResults":"1048",
"Response":"True"
}
I'd like to extract every movie and store it into a List so I've created a class MovieContainer with a List of Movies, where each Movie contains String attributes describing details about said movie e.g. title, year yiddi yadda - you get the drill!
I used the following code snippet to;
MovieContainer cnt = new Gson().fromJson(jstring, MovieContainer.class);
where jstring is a valid json string similar to the json string sample above, but when I try to iterate over the List in the MovieContainer instance I get a NullPointerException.
I'm new to GSON hence not sure what's the cause?
EDIT: I do know what a NullPointerException is, but I don't understand why Java throws it in my example.
My MovieContainer class:
public class MovieContainer {
public List<Movie> movies;
}
My Movie class:
public class Movie {
String Title;
String Year;
String Poster;
String imdbID;
String Type;
}
I'm expecting the call to the fromJson method to fill my List with the information matching the fields' name, but the List movies points is null.

If you want to search for titles first you need to get "Search" inside that data you need to iterate and look for titles.
Because your Gson contains 3 elements, "Search", "totalResults" and "Response".

Your MovieContainer class is missing the other two fields i.e. totalResults and Response which are also part of the root json object.
Here's a quick dirty example to get you up and running. It's based on the information you have provided thus far.
Movie.java
public class Movie {
private String Title;
private String Year;
private String imdbID;
private String Type;
private String Poster;
}
MovieContainer.java
public class MovieContainer {
private List<Movie> Search;
private String totalResults;
private String Response;
public static void main(String[] args) {
// Converts the json to the Java object a.k.a POJO 😎!!!
deserialize();
}
private static void deserialize() {
String jstring = " { " +
" 'Search' : [ " +
" { " +
" 'Title' : 'Seven Pounds', " +
" 'Year' : '2008', " +
" 'imdbID' : 'tt0814314', " +
" 'Type' : 'movie', " +
" 'Poster' : 'someUrl' " +
" }, " +
" { " +
" 'Title' : 'Seven Samurai', " +
" 'Year' : '1954', " +
" 'imdbID' : 'tt0047478', " +
" 'Type' : 'movie', " +
" 'Poster' : 'someUrl' " +
" } " +
" ], " +
" 'totalResults' : '1048', " +
" 'Response' : 'True' " +
" } ";
Gson gson = new Gson();
MovieContainer searchResults = gson.fromJson(jstring, MovieContainer.class);
}
}
A screenshot to confirm the List isn't null are as follows:-
Now time to party see ya!!! 🎉🎉🎉🎉🎉

Related

How can I get names from different JSON objects in a JSON Array for example [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
{
item:[
{
item_id: 1
add_on:[
{
name: Thin Crust
},
{
name: Extra Cheese
},
{
name: Extra Sauce
}
}]
}
I want to get these names and place them into one TextView
First of all you need to correct to JSON input. It's not valid JSON. Correct JSON should be :
{
"item": [{
"item_id": 1,
"add_on": [{
"name": "Thin Crust"
},
{
"name": "Extra Cheese"
},
{
"name": "Extra Sauce"
}
]
}]
}
After that with Jackon library you can get the data from Json in POJO as below:
POJO(s):
class Items {
#JsonProperty("item")
public List<Item> item;
}
class Item {
#JsonProperty("item_id")
public int itemId;
#JsonProperty("add_on")
public List<Name> addOn;
}
class Name {
#JsonProperty("name")
public String name;
}
Conversion with Jackson:
public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
String json = "{\r\n" +
" \"item\": [{\r\n" +
" \"item_id\": 1,\r\n" +
" \"add_on\": [{\r\n" +
" \"name\": \"Thin Crust\"\r\n" +
" },\r\n" +
"\r\n" +
" {\r\n" +
" \"name\": \"Extra Cheese\"\r\n" +
" },\r\n" +
"\r\n" +
" {\r\n" +
" \"name\": \"Extra Sauce\"\r\n" +
" }\r\n" +
" ]\r\n" +
" }]\r\n" +
"}";
Items item = (new ObjectMapper()).readValue(json, Items.class);
System.out.println(item);
}
Now from this object structure you can get names.
First of all include the JSON Library in your project.
Then access your JSON Object like this:
JSONObject jsonObject = new JSONObject(jsonString); // here is your JSON as String
// Get your Json Array of item
JSONArray itemArray = jsonObject.getJSONArray("item");
// Get your first Element from your array
JSONObject firstItem = itemArray.getJSONObject(0);
// Then get your add_on array
JSONArray itemArray = firstItem.getJSONArray("add_on");
// After you get your array Get your second object which is { name: Extra Cheese}
JSONObject secondObject = itemArray.getJSONObject(1);
// Then you get your itemName this way:
String itemName = secondObject.getString("name");

JsonPath expression to find if a key-value pair is not present in a set of JSON objects?

Given the following JSON:
{
"full_report": {
"score": "5",
"history": {
"record": [
{
"name": "John Smith",
"SSN": "123456789",
"last_visit": "02.03.2019",
"expiry_date": "15.03.2019"
},
{
"name": "John Doe",
"SSN": "987654321",
"last_visit": "05.03.2019",
"expiry_date": "15.09.2019"
},
{
"name": "Jane Doe",
"SSN": "999999999",
"last_visit": "02.03.2019"
}
]
}
}
}
I would like to be able to use JsonPath to find if any of the objects under the record array are missing the expiry_date key and value pair. I currently have a working solution using a method that adds all entries of record to one list and all entries of expiry_date to another and simply checks if the subtraction of both list sizes equals 0 to return a boolean value.
public Boolean isMissing(String json, String expression) {
String[] expr = expression.split(";");
List<String> totalRecords = JsonPath.read(json, expr[0]);
List<String> foundRecords = JsonPath.read(json, expr[1]);
return totalRecords.size() - foundRecords.size() != 0;
}
This requires using two JsonPath expressions with a ; delimiter like so which causes some other, unrelated issues that I'd like to avoid:
$.full_report.history.record[?(#.expiry_date)];$.full_report.history.record[*]
For a copy of this exact structure in XML I can use an XPath expression like so: boolean(full_report/history/record[not(expiry_date/text())])
Any chance there's an equivalent filter that I may have missed in JsonPath?
Update
The answer below by Saeed Alizadeh to use predicate does not solve the problem of having to pass in the property to look for in the first place.
It did help make the method and passing in the property a fair bit cleaner as there's no longer a need to write two separate expressions rather than expression;property_to_lookup. As seen in the method below, that fundamental issue still remains but is much more hassle-free:
public Boolean isMissing(String json, String expression) {
String[] expressionAndPredicate = expression.split(";");
Predicate missingKeyValue = predicateContext -> {
Object missingKey = predicateContext.item(Map.class).get(expressionAndPredicate[1]);
return missingKey == null || missingKey.toString().length() <= 0;
};
List<String> records = JsonPath.read(json, expressionAndPredicate[0], missingKeyValue);
return records.size() != 0;
}
I don't want to add a 3rd parameter to the method for the property nor split the incoming string to sidestep the issue as it creates some issues when providing the JsonPath expression as input at the endpoint. If no one-line expression exists similar to the XPath example, I'll mark the question as answered by Saeed.
As you can see example below by using predicate you can filter result:
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Predicate;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String json = "{\n" +
" \"full_report\": {\n" +
" \"score\": \"5\",\n" +
" \"history\": {\n" +
" \"record\": [\n" +
" {\n" +
" \"name\": \"John Smith\",\n" +
" \"SSN\": \"123456789\",\n" +
" \"last_visit\": \"02.03.2019\",\n" +
" \"expiry_date\": \"15.03.2019\"\n" +
" },\n" +
" {\n" +
" \"name\": \"John Doe\",\n" +
" \"SSN\": \"987654321\",\n" +
" \"last_visit\": \"05.03.2019\",\n" +
" \"expiry_date\": \"15.09.2019\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Jane Doe\",\n" +
" \"SSN\": \"999999999\",\n" +
" \"last_visit\": \"02.03.2019\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
"}";
Predicate expiry_date = new Predicate() {
public boolean apply(PredicateContext predicateContext) {
Object expiry_date = predicateContext.item(Map.class).get("expiry_date");
return expiry_date != null && expiry_date.toString().length() > 0 ? false : true;
}
};
List records = JsonPath.parse(json).read("full_report.history.record[?]", List.class, expiry_date);
System.out.println(records);
}
}
this will print following output as the only record missing "expiry_date" property
[{"name":"Jane Doe","SSN":"999999999","last_visit":"02.03.2019"}]
update
public static boolean isMissing(String json, final String jsonProperty) {
Predicate predicate = new Predicate() {
public boolean apply(PredicateContext predicateContext) {
Object propertyObject = predicateContext.item(Map.class).get(jsonProperty);
return propertyObject != null && propertyObject.toString().length() > 0 ? false : true;
}
};
List records = JsonPath.parse(json).read("full_report.history.record[?]", List.class, predicate);
return (records != null && records.size() > 0) ? true : false;
}
output:
System.out.println(isMissing(json, "expiry_date")); // prints true
System.out.println(isMissing(json, "name")); // prints false

How to grab data from a class without making it static per say [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
So for example I have this class that outputs my detailed flight output that is in the java doc "Flight.java" :
public String toDetailedString() {
String output =
getDeparture() + " - " + getArrival() + "\n" + Airport.getAirportCity(source) + " (" +
source + ") - " + Airport.getAirportCity(destination) + " (" + destination + ")" +
"\n" + plane.getAirline() + " " + number + " * " + plane.getModel();
return output;
}
and I have an Itinerary class "Itinerary.java" and I want to pull the info from Flight.java without making toDetailedString static, is that possible?
For added info, each of the variables you see "source, number, destination" are all private variables in Flight.java which I know are enclosed encapsulation. Any help is greatly valuable.
Example implementation in Itinerary.java
public String toString() {
return "The total cost is" + getTotalCost() + Flight.toDetailedString();
}
UPDATE:
In my Flight constructor I have:
public Flight(Plane plane, String number, double cost, Time departure, int duration, Airport source, Airport destination) {
this.plane = plane;
this.number = number;
this.cost = cost;
this.departure = departure;
this.duration = duration;
this.source = source;
this.destination = destination;
}
In which I created the object "f1" in my ItineraryTest class:
Flight f1 = new Flight(new Plane(Airline.American, "Airbus A321"),
"495",
79,
new Time(7, 10), 100,
Airport.PHX, Airport.LAX);
Thus I linked my object to the toDetailedString() the object "f1" was renamed to "first" in my Itinerary.java and a second object was created called "f2" and moved to "second" (to avoid confusion) :
public String toString() {
return "The total cost: "
+ getTotalCost()
+ " "
+ first.toDetailedString()
+ second.toDetailedString();
}
I thought I answered my own question, but now receive an error of:
Exception in thread "main" java.lang.NullPointerException at
Itinerary.toString(Itinerary.java:117) at
java.lang.String.valueOf(String.java:2994) at
java.io.PrintStream.println(PrintStream.java:821) at
ItineraryTest.main(ItineraryTest.java:20)
Possible, clean option is creating another class named FlightToDetailedString, with (possibly static) method toDetailedString. That method would accept instance of Flight as parameter
class FlightToDetailedString {
public String toDetailedString(Flight flight) {
String output =
getDeparture() + " - " + getArrival() + "\n" + Airport.getAirportCity(source) + " (" +
source + ") - " + Airport.getAirportCity(destination) + " (" + destination + ")" +
"\n" + plane.getAirline() + " " + number + " * " + plane.getModel();
return output;
}
}
In my example method is not static. With non-static member mehod, FlightToDetailedString could have (and use in toDetailedString) fields of FlightToDetailedString class. For example, Airport could be member variable of FlightToDetailedString. Are you sure you want to limit yourself to one airport?
Why you do not like toDetailedString as non-static member of Flight class in first place? In example you give it is most natural solution. if your Itinerary needs to access details of Flight class, just pass instance of Flight object as argument!
The consumer of toDetailedString() doesn't need access to anything inside Flight.
Your NullPointerException is likely caused by one of the fields in the Flight instance being null.
Finally, consider using a StringBuilder instead of concatenating strings.

JAVA - is it possible to filter the sub elements of JSON Object that is large & recursive ??

I want some help to find a quick solution for my problem. Given a json object that is large with a recursive model. I want to list the JSON sub elements & its immediate parent Object( only the sub object which satisfies the given key value condition).
Ex :
{
Object : {
id : "0001",
parent:"A",
child: {
id:"0001A",
Country:"US",
parent:"B",
child:{
id:"0001AA",
Country:"UK",
parent:"C",
child:{
id:"0000AAA",
Country:"US",
parent:"D",
child:{
.........
}
}
}
}
}
}
I want to list the id's of the subObject whose country is 'US' and it's parent id..
is there available any readymade plugins to handle these kind of scenarios in JAVA , without using object mappers/custom class objects..
Ps provide any possible idea ..
Yes, it is possible write code using the Jackson Tree Model API which would traverse a JSON tree and select the nodes that satisfy criteria. Here is an example:
public class JacksonTree2 {
public static final String JSON = "{\"Ex\" : {\"Object\" : {\n" +
" \"id\" : \"0001\",\n" +
" \"parent\":\"A\",\n" +
" \"child\": {\n" +
" \"id\":\"0001A\",\n" +
" \"Country\":\"US\",\n" +
" \"parent\":\"B\",\n" +
" \"child\":{\n" +
" \"id\":\"0001AA\",\n" +
" \"Country\":\"UK\",\n" +
" \"parent\":\"C\",\n" +
" \"child\":{\n" +
" \"id\":\"0000AAA\",\n" +
" \"Country\":\"US\",\n" +
" \"parent\":\"D\",\n" +
" \"child\":{\n" +
" \n" +
" }\n" +
" }\n" +
" }\n" +
"\t}\n" +
"}}}";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(JSON);
for (JsonNode node : root.findParents("Country")) {
if ("UK".equals(node.get("Country").asText())) {
System.out.println(node.get("id"));
break;
}
}
}
}
Output:
"0001AA"

Help with toString() - adding to collections

I am adding information from main()
I am adding different information for CD, DVD, book..
I have 3 separate classes - item has 3 classes in it...
project - main()
Library - this function does all the adding
Item(cd,dvd,book) inheritance
For Music i am adding band info, title info, keywords, and members..
I am adding members separately than of the other info..
As you can see the members is not outputing correctly as the others..
>>> music CDs:
-Music-
band: Jerry Garcia Band
# songs: 15
members: [Ljava.lang.String;#61de33
title: Don't Let Go
C:\Java\a03>
I am using the same toString() function for members as i am the rest, so i am not sure why it would do this..
I will give you as much info as i think you need to see..
Main() - as you can see it calls 2 different functions.
the addbandmembers is where i am having problems...
out.println(">>> adding items to library:\n");
item = library.addMusicCD("Europe In '72", "Grateful Dead", 12, "acid rock", "sixties", "jam bands");
if (item != null) {
library.addBandMembers(item, "Jerry Garcia", "Bill Kreutzman", "Keith Godcheaux");
library.printItem(out, item);
}
in Library class - here is the addbandmember function ..
Could this be the cause??
public void addBandMembers(Item musicCD, String... members)
{
((CD)musicCD).addband(members);
}
In the Items class here is the function addband - tostring()
here is the CD class which extends the items class..
class Item
{
private String title;
public String toString()
{
String line1 = "title: " + title + "\n";
return line1;
}
public void print()
{
System.out.println(toString());
}
public Item()
{}
public Item(String theTitle)
{
title = theTitle;
}
public String getTitle()
{
return title;
}
}
class CD extends Item
{
private String artist;
private String [] members;
private int number;
public CD(String theTitle, String theBand, int Snumber, String... keywords)
{
super(theTitle);
this.artist = theBand;
this.number = Snumber;
}
public void addband(String... member)
{
this.members = member;
}
public String getArtist()
{
return artist;
}
public String [] getMembers()
{
return members;
}
public String toString()
{
return "-Music-" + "\n" + "band: " + artist + "\n" + "# songs: " + number + "\n" + "members: " + members + "\n" + "\n" + super.toString() + "\n";
}
public void print()
{
System.out.println(toString());
}
}
I do have other information in the items class like a nook class, movie class that i didnt show. I would like to keep everything the way i have it set up..
So, if the other items are printing fine than maybe its the cast in the addbandmember function thats giving me problems?
members is printing the way it is since it's an array (you can tell this by the fact its output as members: [Ljava.lang.String;#61de33 ).
Instead you need to iterate through it and print each element.
e.g.
for (String member : members) {
...
}
The simplest way is to use Arrays.toString(). Alternatively append to a StringBuilder and then print to this. You can be cleverer, and use StringUtils.join() from Apache Commons Lang, which will give you more control.
Arrays don't have a useful toString() implementation. You can print out the members in a loop or use the Arrays.toString() method to do this for you:
return "-Music-" + "\n"
+ "band: " + artist + "\n"
+ "# songs: " + number + "\n"
+ "members: " + Arrays.toString(members) + "\n"
+ "\n"
+ super.toString() + "\n";

Categories

Resources