Assignments Office Hours Hall of Fame Notes
Assignments Office Hours Hall of Fame Notes

Serialized Sportsball

Assigned: 2019-09-05
Due Date: 2019-09-10 by 11:59PM U.S. Central Time

What a save!
What a save!
What a save!
Chat disabled for 4 seconds

— Rocket League

It's your first day on the job at Sportsbridge Analytica, a popular data analysis firm, and your boss is already breathing down your neck: he wants to make a strong impression on some potential investors, so he's tasked you (lucky, lucky!) to analyze a file that he says describes every play made during a soccer game. He wants to you get back to him with "some statistics," whatever that means. Fortunately for you, we're here to help you through it!

Upon closer inspection, you realize that the file is just JSON. Hooray! Intrepid CS 126 student that you are, you know that if you use Google's GSON to turn the JSON into Java objects, you can easily analyze the data and provide your boss the statistics he needs to amaze his investors! And secure the Epic Victory Royale!

Goals

Background Info

Serializing (or marshalling) is the process of converting objects in code into a different representation for storage, whether that's JSON, YAML, binary data, or something else. Deserializing (or unmarshalling) is the reverse: converting serialized data into actual objects in your code. In this case, we are transmitting serialized data about a soccer game to you, so that you can deserialize it into Java objects for processing.

A schema is a definition of how to represent some data. For example, if we want to describe a course at UIUC in words we might say the following:

There is a natural translation between a schema describing objects stored in JSON and objects in Java.

JSON

The soccer game data is stored as JSON, a data format popularized by the JavaScript programming language. Here's an example of some JSON, representing a group of courses at UIUC:

{
    "courses": [
        {
            "department": "Computer Science",
            "number": 126,
            "isDifficult": false,
            "isTimeConsuming": true,
            "professors": ["Craig Zilles", "Carl Evans", "Michael Woodley"]
        },
        {
            "department": "Computer Science",
            "number": 421,
            "isDifficult": true,
            "isTimeConsuming": false,
            "professors": ["Elsa Gunter", "Mattox Beckman"]
        }
    ]
}

Things to note about syntactically valid JSON:

The JSON we're providing to you is already valid, so you don't need to worry about any of this unless you want to edit or write your own JSON for testing purposes. If you want to check that your JSON is valid, you can use a JSON validator like this one.

GSON

Rather than having you parse JSON all by yourself, you're going to use Google's GSON library to do it for you. GSON is already included in your project; all you have to do is import and use it.

If we have some JSON like above, we need to define some Java classes that match the schema so that GSON can deserialize the JSON into instances of those objects.

First, we define the outermost class with its fields:

public class UiucCourses {
    private List<Course> courses;

    // -- Getter methods omitted --
}

Then we define the inner class, with its own fields:

public class Course {
    private String department;
    private int number;
    private boolean isDifficult;
    private boolean isTimeConsuming;
    private String[] professors;

    // -- Getter methods omitted --
}

Finally, we deserialize our JSON into an instance of UiucCourses:

String myJson = "....."; // Read in JSON from somewhere...

Gson gson = new Gson(); // Create an instance of a GSON parser
UiucCourses courses = gson.fromJson(myJson, UiucCourses.class);

Note that you can define your collections as either Object[] or List<Object> at your preference, and GSON will convert it to the appropriate format.

If you need more documentation and examples on how to use GSON, see the User's Guide.

JUnit's @Before

As with the previous assignment, we expect you to write unit tests as you develop. We're going to introduce a new feature of JUnit to make writing some kinds of tests easier for you: the @Before annotation.

Here's the motivation: your unit tests should be self contained so that running one test doesn't influence the results of another. When you have objects that are shared between tests, that can be hard to guarantee. When you apply the @Before annotation to a function in your testing class, it tells JUnit that it should run that function once before each and every one of your unit tests, so we can use an @Before-annotated method to reset any necessary state between test cases.

Specifically, this is great for tests involving GSON:

public class UiucCoursesTest {
    private Gson gson;

    @Before
    public void setUp() {
        gson = new Gson();
    }

    @Test
    public void testCaseOne() {
        gson.fromJson(/* ... */);
    }

    @Test
    public void testCaseTwo() {
        gson.fromJson(/* ... */);
    }
}

Now we don't have to repeat the line Gson gson = new Gson() in all of our tests, and the GSON instance will be reset before each and every one of our unit tests. For more information, see JUnit's documentation.


Getting Started

Get your copy of the assignment by visiting this GitHub link: https://classroom.github.com/a/E0vpSHyB

The JSON data you'll be analyzing is hosted here: https://courses.grainger.illinois.edu/cs126/fa2019/assignments/sportsball.json

You may download a copy of this data to use in your development process and for testing, but you should avoid copy-pasting the JSON into your code.

Part 1: Deserialization

In order to do anything meaningful with the data in Java, you have to convert it into Java objects. You will do this using Google's GSON, a JSON serializing/deserializing library.

Specifically you should:

Part 2: Processing and Analyzing the Data

Once you have your data as Java objects, you need to be able to filter and process it to get more interesting results. Specifically, you need to create:

You do not have to implement these specific examples.

For the purposes of this assignment, a filtering function takes in a collection and produces another collection with the same number or fewer elements. An analysis function gives you some kind of result, whether that result is a list or a number or a boolean.

The functions should not mutate any of the data they operate on; they should return new collections/numbers/objects as necessary.

This assignment is deliberately open-ended with regards to how you choose to implement the filtering and analysis functions; design decisions like what kinds of classes and functions to write are left up to you. Be creative! We have avoided giving you any starter code to encourage you to reason about how to organize your project.

We have provided you with a single helper method for the purpose of reading in a file as a String, which you may freely use in your development process and tests. There is a unit test demonstrating its usage.

Deliverables and Grading

As always, try to use the best code design and coding style. Continue to focus on writing good names (you have a lot of freedom in naming for this assignment) and think about how to cleanly lay out your code so that it's easy for an outsider (your moderator) to follow. You might find Chapter 4 of the textbook and Section 4 of the Google Java Style Guide to be good resources for this.

As you work on this project, you should commit small pieces of functionality as you write them. Don't make a single mega-commit at the very end! We expect your commit history to demonstrate you following some sort of iterative design process. For example: writing some tests, writing some code, changing some tests, fixing a test, writing more code, etc. Commits are cheap. Make lots of them!

Specific things we will be checking for: