Java 2

Week 4

Topics Covered

  • JSON file input
  • Operations with open source APIs

What is JSON?

  • JavaScript Object Notation (JSON) is a text file format for storing and transmitting data objects.
  • JSON filenames use the extension .json
  • JSON can be used to get data for Java objects
  • A JavaScript object starts with { and ends with } 
  • Between the curly brackets are key:value pairs
    • keys must be strings
    • values can be strings, arrays, or objects
    • each key value pair must be separated by a comma.
  • Below is an example of JSON representing a Message object.
  • Here is a more complex example representing a Person object.
{role: "test", content: "example"}

JSON Dependency

  • To read JSON, you need to add a dependency to the pom.xml file
  • Create a new Java file called JsonDemo1. Add this code.
  • I am assigning the JSON string to a variable called responseBody to represent an HTTP response from a web server.
import com.google.gson.Gson;

public class JsonDemo1 {
    public static void main(String[] args) throws Exception {
        String responseBody = "{role: \"test\", content: \"example\"}";
        Gson gson = new Gson();
        Message message = gson.fromJson(responseBody, Message.class);
        System.out.println(message.role);
        System.out.println(message.content);
    }

    private static class Message {
        private String role;
        private String content;
    }
}

Handling Invalid JSON

  • In this example, I removed the comma from the string to make invalid JSON.
  • The fromJson() method throws a JsonSyntaxException when invalid JSON is found.
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

public class JsonDemo1 {
    public static void main(String[] args) throws Exception {
        String responseBody = "{role: \"test\" content: \"example\"}";
        Gson gson = new Gson();
        Message message = null;
        try {
            message = gson.fromJson(responseBody, Message.class);
        } catch(JsonSyntaxException e) {
            System.out.println("ERROR: " + e.getMessage());
            System.exit(0);
        }
        System.out.println(message.role);
        System.out.println(message.content);
    }

    private static class Message {
        private String role;
        private String content;
    }
}

JSON Dependencies

What is an API?

  • An application programming interface (API) is a way for two or more programs to communicate with each other.
  • APIs offer data and services to other pieces of software.
  • An API dictates how to write code to take advantage of that system's capabilities.

HTTP Dependency

  • To read JSON from a web server, you need to add a second dependency to the pom.xml file
  • Create a new Java file called JsonDemo2. Add this code.
  • In this example, I only obtain the Person object's first name, last name, and email address.
import com.google.gson.Gson;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;


public class JsonDemo2 {
    private static final String API_URL = "https://randomuser.me/api/?format=json&seed=abc&results=1&nat=us";

    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(API_URL)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);
        Gson gson = new Gson();
        APIResponse apiResponse = gson.fromJson(responseBody, APIResponse.class);
        for (Person person : apiResponse.results) {
            System.out.println(person.name.first + " " + person.name.last);
            System.out.println(person.email);
        }
    }

    private static class APIResponse {
        private Person[] results;
    }

    private static class Person {
        private Name name;
        private String email;
    }

    private static class Name {
        private String first;
        private String last;
    }
}

Get More Data

  • In this example, I add the Person object's location and street address.
import com.google.gson.Gson;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;


public class JsonDemo2 {
    private static final String API_URL = "https://randomuser.me/api/?format=json&seed=abc&results=1&nat=us";

    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(API_URL)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);
        Gson gson = new Gson();
        APIResponse apiResponse = gson.fromJson(responseBody, APIResponse.class);
        for (Person person : apiResponse.results) {
            System.out.println(person.name.first + " " + person.name.last);
            System.out.printf("%d %s\n", person.location.street.number, person.location.street.name);
            System.out.printf("%s, %s %s\n", person.location.city, person.location.state, person.location.postcode);
            System.out.printf("Latitude: %.4f, Longitude: %.4f\n", person.location.coordinates.latitude, person.location.coordinates.longitude);
            System.out.println(person.email);
        }
    }

    private static class APIResponse {
        private Person[] results;
    }

    private static class Person {
        private Name name;
        private Location location;
        private String email;
    }

    private static class Name {
        private String first;
        private String last;
    }

    private static class Location {
        private Street street;
        private String city;
        private String state;
        private int postcode;
        private Coordinates coordinates;
    }

    private static class Street {
        private int number;
        private String name;
    }

    private static class Coordinates {
        private double latitude;
        private double longitude;
    }
}

Handling Exceptions

  • In this example, I try to assign a String to an int.
  • If you have an attribute that doesn't exist, it will be assigned its default value (Object is null, int is 0, etc.)
package edu.kirkwood;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;


public class JsonDemo2 {
    private static final String API_URL = "https://randomuser.me/api/?format=json&seed=abc&results=1&nat=us";

    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(API_URL)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);
        Gson gson = new Gson();
        APIResponse apiResponse = null;
        try {
            apiResponse = gson.fromJson(responseBody, APIResponse.class);
        } catch(JsonSyntaxException e) {
            System.out.println("ERROR: " + e.getMessage());
            System.exit(0);
        }
        for (Person person : apiResponse.results) {
            System.out.println(person.name.first + " " + person.name.last);
            System.out.printf("%d %s\n", person.location.street.number, person.location.street.name);
            System.out.printf("%s, %s %s\n", person.location.city, person.location.state, person.location.postcode);
            System.out.printf("Latitude: %.4f, Longitude: %.4f\n", person.location.coordinates.latitude, person.location.coordinates.longitude);
            System.out.println(person.email);
        }
    }

    private static class APIResponse {
        private Person[] results;
    }

    private static class Person {
        private Name name;
        private Location location;
        private String email;
    }

    private static class Name {
        private String first;
        private String last;
    }

    private static class Location {
        private Street street;
        private String city;
        private String state;
        private int postcode;
        private Coordinates coordinates;
    }

    private static class Street {
        private int number;
        private int name;
    }

    private static class Coordinates {
        private double latitude;
        private double longitude;
    }
}

Handling Dates

import com.google.gson.*;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.lang.reflect.Type;
import java.time.Instant;

public class JsonDemo2 {
    private static final String API_URL = "https://randomuser.me/api/?format=json&seed=abc&results=1&nat=us";

    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(API_URL)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Instant.class, new InstantDeserializer())
                .create();
        APIResponse apiResponse = null;
        try {
            apiResponse = gson.fromJson(responseBody, APIResponse.class);
        } catch(JsonSyntaxException e) {
            System.out.println("ERROR: " + e.getMessage());
            System.exit(0);
        }
        for (Person person : apiResponse.results) {
            System.out.println(person.name.first + " " + person.name.last);
            System.out.printf("%d %s\n", person.location.street.number, person.location.street.name);
            System.out.printf("%s, %s %s\n", person.location.city, person.location.state, person.location.postcode);
            System.out.printf("Latitude: %.4f, Longitude: %.4f\n", person.location.coordinates.latitude, person.location.coordinates.longitude);
            System.out.println(person.email);
            System.out.printf("Born %s\n", person.dob.date);
        }
    }

    private static class InstantDeserializer implements JsonDeserializer<Instant> {
        @Override
        public Instant deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
            return Instant.parse(json.getAsString());
        }
    }

    private static class APIResponse {
        private Person[] results;
    }

    private static class Person {
        private Name name;
        private Location location;
        private String email;
        private DateOfBirth dob;
    }

    private static class Name {
        private String first;
        private String last;
    }

    private static class Location {
        private Street street;
        private String city;
        private String state;
        private int postcode;
        private Coordinates coordinates;
    }

    private static class Street {
        private int number;
        private String name;
    }

    private static class Coordinates {
        private double latitude;
        private double longitude;
    }

    private static class DateOfBirth {
        private Instant date;
    }
}

Comparing and Sorting

  • Implement the Comparable Interface in the RandomUser class.
  • Before printing users, sort them alphabetically.
import com.google.gson.*;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.lang.reflect.Type;
import java.time.Instant;
import java.util.Arrays;

public class JsonDemo2 {
    private static final String API_URL = "https://randomuser.me/api/?format=json&seed=abc&results=5&nat=us";

    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url(API_URL)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Instant.class, new InstantDeserializer())
                .create();
        APIResponse apiResponse = null;
        try {
            apiResponse = gson.fromJson(responseBody, APIResponse.class);
        } catch(JsonSyntaxException e) {
            System.out.println("ERROR: " + e.getMessage());
            System.exit(0);
        }
        Person[] people = apiResponse.results;
        Arrays.sort(people);
        for(Person person: people) {
            System.out.println(person.name.first + " " + person.name.last);
            System.out.printf("%d %s\n", person.location.street.number, person.location.street.name);
            System.out.printf("%s, %s %s\n", person.location.city, person.location.state, person.location.postcode);
            System.out.printf("Latitude: %.4f, Longitude: %.4f\n", person.location.coordinates.latitude, person.location.coordinates.longitude);
            System.out.println(person.email);
            System.out.printf("Born %s\n", person.dob.date);
            System.out.println();
        }
    }

    private static class InstantDeserializer implements JsonDeserializer<Instant> {
        @Override
        public Instant deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
            return Instant.parse(json.getAsString());
        }
    }

    private static class APIResponse {
        private Person[] results;
    }

    private static class Person implements Comparable<Person> {
        private Name name;
        private Location location;
        private String email;
        private DateOfBirth dob;
        
        @Override
        public int compareTo(Person o) {
            int result = this.name.last.compareTo(o.name.last);
            if (result == 0) {
                result = this.name.first.compareTo(o.name.first);
            }
            return result;
        }
    }

    private static class Name {
        private String first;
        private String last;
    }

    private static class Location {
        private Street street;
        private String city;
        private String state;
        private int postcode;
        private Coordinates coordinates;
    }

    private static class Street {
        private int number;
        private String name;
    }

    private static class Coordinates {
        private double latitude;
        private double longitude;
    }

    private static class DateOfBirth {
        private Instant date;
    }
}

JSON Dependencies

  • Instead of Square OkHttp, you can add this dependency to the pom.xml file
  • Here is some sample code to try.
    https://www.baeldung.com/java-http-response-body-as-string

Movie API

import com.google.gson.*;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.lang.reflect.Type;
import java.time.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JsonDemo3 {
    public static void main(String[] args) throws IOException {
        // Remove before pushing to GitHub
        String apiKey = "";

        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://api.themoviedb.org/3/trending/movie/day?language=en-US")
                .get()
                .addHeader("accept", "application/json")
                .addHeader("Authorization", "Bearer " + apiKey)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);

        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(LocalDate.class, new LocalDateDeserializer())
                .create();
//        JsonElement jsonElement = new JsonParser().parse(responseBody);
//        String json = gson.toJson(jsonElement);
//        System.out.print(json);
        MovieDBAPI movieDBAPI = null;
        try {
            movieDBAPI = gson.fromJson(responseBody, MovieDBAPI.class);
        } catch (JsonSyntaxException | JsonIOException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }

        for(Movie movie : movieDBAPI.results) {
            System.out.println("ID: " + movie.id);
            System.out.println("Title: " + movie.title);
            System.out.println("Overview: " + movie.overview);
            System.out.println("Genres: " + Arrays.toString(movie.genre_ids));
            System.out.println("Vote Average: " + movie.vote_average);
            System.out.println("Video: " + (movie.video ? "Yes" : "No"));
            System.out.println("Release Date: " + movie.release_date);
            System.out.println();
        }
    }

    private static class LocalDateDeserializer implements JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
            return LocalDate.parse(json.getAsString());
        }
    }

    private static class MovieDBGenre {
        public Genre[] genres;
    }
    private static class Genre {
        public int id;
        public String name;
    }

    private static class MovieDBAPI {
        public Movie[] results;
    }
    private static class Movie {
        public int id;
        public String title;
        public String overview;
        public int[] genre_ids;
        public double vote_average;
        public boolean video;
        public LocalDate release_date;
    }
}

Genre Ids to Genres

  • Make a second API request to get Genre data.
  • Use this solution to convert the array of Genre objects into a List<Genre>.
  • Use this solution to retrieve a Genre by its id.
  • The filter() method requires a Predicate object
    • The object of type T is a Genre object.
    • -> indicates a lamba expression
    • The value after the -> must be a boolean expression.
import com.google.gson.*;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.lang.reflect.Type;
import java.time.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JsonDemo3 {
    public static void main(String[] args) throws IOException {
        // Remove before pushing to GitHub
        String apiKey = "";

        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://api.themoviedb.org/3/trending/movie/day?language=en-US")
                .get()
                .addHeader("accept", "application/json")
                .addHeader("Authorization", "Bearer " + apiKey)
                .build();

        Request request2 = new Request.Builder()
                .url("https://api.themoviedb.org/3/genre/movie/list?language=en")
                .get()
                .addHeader("accept", "application/json")
                .addHeader("Authorization", "Bearer " + apiKey)
                .build();

        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
//        System.out.println(responseBody);

        Response response2 = client.newCall(request2).execute();
        String responseBody2 = response2.body().string();
//        System.out.println(responseBody2);

        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .registerTypeAdapter(LocalDate.class, new LocalDateDeserializer())
                .create();
//        JsonElement jsonElement = new JsonParser().parse(responseBody);
//        String json = gson.toJson(jsonElement);
//        System.out.print(json);
        MovieDBAPI movieDBAPI = null;
        try {
            movieDBAPI = gson.fromJson(responseBody, MovieDBAPI.class);
        } catch (JsonSyntaxException | JsonIOException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }

        MovieDBGenre movieDBGenre = null;
        try {
            movieDBGenre = gson.fromJson(responseBody2, MovieDBGenre.class);
        } catch (JsonSyntaxException | JsonIOException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }
        Genre[] genres = movieDBGenre.genres;
        List<Genre> genresList = Arrays.asList(genres);

        for(Movie movie : movieDBAPI.results) {
            System.out.println("ID: " + movie.id);
            System.out.println("Title: " + movie.title);
            System.out.println("Overview: " + movie.overview);
//            System.out.println("Genres: " + Arrays.toString(movie.genre_ids));
            System.out.print("Genres: ");
            for(int id: movie.genre_ids){
                Genre genre = genresList.stream().filter(a -> a.id == id).collect(Collectors.toList()).get(0);
                System.out.print(genre.name + ", ");
            }
            System.out.println();
            System.out.println("Vote Average: " + movie.vote_average);
            System.out.println("Video: " + (movie.video ? "Yes" : "No"));
            System.out.println("Release Date: " + movie.release_date);
            System.out.println();
        }
    }

    private static class LocalDateDeserializer implements JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
            return LocalDate.parse(json.getAsString());
        }
    }

    private static class MovieDBGenre {
        public Genre[] genres;
    }
    private static class Genre {
        public int id;
        public String name;
    }

    private static class MovieDBAPI {
        public Movie[] results;
    }
    private static class Movie {
        public int id;
        public String title;
        public String overview;
        public int[] genre_ids;
        public double vote_average;
        public boolean video;
        public LocalDate release_date;
    }
}

Java 2 - Week 4

By Marc Hauschildt

Java 2 - Week 4

  • 243