Lesson Weekend

Alright! We've identified our goal: creating an awesome restaurant API. We also have user stories to fuel our approach. Next, we can begin deciding what our data needs to look like to fulfill those goals.

Let's check our Trello board, and move these tasks into the "In Progress" column, as these user stories are being worked on by creating our data model:

C. As a user, I want to see specific information such as the Restaurant's name, address, phone number, website, and email
I. As an admin, I want to be able to add a Restaurant to the database
g

Sketching our Data Model

Because we were so thorough sketching out our user's needs, determining our data model is actually a fairly easy process. It's our data and what our users want to see that should determine how we go about structuring our functionality. We can fine tune later if we realize we didn't take something into account.

Here's what I came up with:

3 classes: Restaurant, Foodtype and Review. We'll avoid creating a User class to keep things simple for now.

Time for…A new project, and...a new POJO! And another. And another.

  • Let's start a brand new app, and call it Jadle. We'll add readme and .gitignore files right away.

  • Next, let's create our App.java, and add the dependencies we need to our build.gradle.

We won't be using handlebars, since our API will be returning JSON rather than displaying templates. That means we can go ahead and remove compile "com.sparkjava:spark-template-handlebars:2.5.5" from our dependencies list.

Here's what our build.gradle dependencies should look like.

build.gradle
dependencies {
  testCompile group: 'junit', name: 'junit', version: '4.12'
  compile "com.sparkjava:spark-core:2.6.0"
  compile 'org.slf4j:slf4j-simple:1.7.21'
  compile group: 'org.sql2o', name: 'sql2o', version: '1.5.4'
  compile group: 'com.h2database', name: 'h2', version: '1.4.191'
}

When you are done with that, go ahead and create a models package, and a new Restaurant.java class within models.

  • Then, we'll generate a test file for Restaurant.java with a setUp and tearDown annotation. This should of course be RestaurantTest.

Alright, so, which properties should our Restaurant object have? Here is what we settled on:

src/main/java/models/Restaurant.java
package models;

public class Restaurant {

   private String name;
   private String address;
   private String zipcode;
   private String phone;
   private String website;
   private String email;
   private int id;
}

Great. This is plenty for now.

Let's generate a constructor that takes arguments for everything except the id. We'll set that later from the database, just like we did with our To Do List.

src/main/java/models/Restaurant.java
package models;

public Restaurant(String name, String address, String zipcode, String phone, String website, String email) {
    this.name = name;
    this.address = address;
    this.zipcode = zipcode;
    this.phone = phone;
    this.website = website;
    this.email = email;
}

Constructor Overloading

But wait; what if a Restaurant we want to add doesn't have an email or website? Smaller, more old-school places may not have these things, and it seems unfair to penalize them for that.

It would be nice if we could set default text that reads "no website available" if the user doesn't supply that information. We could write logic to handle this, but let's try a different approach instead: we'll write a second constructor that accepts a different amount of arguments.

Generate a second constructor above the first that ONLY accepts arguments for name, address, zip, and phone. Our code should look now like this:

src/main/java/models/Restaurant.java
package models;

public class Restaurant {

  private String name;
  private String address;
  private String zipcode;
  private String phone;
  private String website;
  private String email;
  private int id;

   public Restaurant(String name, String address, String zipcode, String phone) {
       this.name = name;
       this.address = address;
       this.zipcode = zipcode;
       this.phone = phone;
   }

   public Restaurant(String name, String address, String zipcode, String phone, String website, String email) {
       this.name = name;
       this.address = address;
       this.zipcode = zipcode;
       this.phone = phone;
       this.website = website;
       this.email = email;
   }
}

This is pretty cool. Because Java is so strict about the amount and type of arguments supplied to a constructor, we can actually make two (or many) subtly different constructors! The amount and type of arguments a method (including a constructor) takes are called its method signature. (Remember this term! It often comes up in interview questions.)

You've likely already seen this in your own work in IntelliJ; the code completion sometimes offers us many methods that have the same name, but are all subtly different - they take different arguments, and this is why. The technical term is constructor overloading.

Note: IntelliJ is generally happier if the constructor requiring fewer arguments is placed above the constructor with more arguments. This seems to work better with regards to code completion. Java itself doesn't care.

Let's set some default properties in our first constructor:

src/main/java/models/Restaurant.java
package models;

   public Restaurant(String name, String address, String zipcode, String phone) {
       this.name = name;
       this.address = address;
       this.zipcode = zipcode;
       this.phone = phone;
       this.website = "no website listed";
       this.email = "no email available";
   }

We can still set the object's properties though if we wanted to (say, if a Restaurant suddenly needed to add a website), just like we were able to set id after the fact in To Do List.

Now, if a user doesn't supply a website or email from the get go, we'll create an object using one constructor. If they do, we'll create it using another constructor. Cool!

Let's go ahead and add some tests into our RestaurantTest class to check our getters and setters. You can create them on your own, or grab them from the cheat sheet. We should feel very comfortable testing getters and setters now.

When you are done, go ahead and generate getters and setters for your Restaurant class too, as well as equals() and hashCode().

Now that we have successfully created our Restaurant class, let's repeat this process for our Review and Foodtype class.

Based on our user stories, our data models should look like this:

src/main/java/models/Review.java
package models;

public class Review {
  private String content;
  private String writtenBy;
  private int rating;
  private int id;
  private int restaurantId; //will be used to connect Restaurant to Review (one-to-many)

  public Review(String content, String writtenBy, int rating, int restaurantId) {
    this.content = content;
    this.writtenBy = writtenBy;
    this.rating = rating;
    this.restaurantId = restaurantId;
  }
}

Also generate the following for Review:

  • getters and setters
  • equals() and hashCode()
src/main/java/models/Foodtype.java
package models;

public class Foodtype {
  private String name;
  private int id;

  public Foodtype(String name) {
    this.name = name;
  }
}

Also generate the followowing for Foodtype:

  • getters and setters,
  • equals() and hashCode()

We also need to generate the test files for both of these classes.

We're getting so good at this!

Check the repo link below if you are not sure what this should look like, but this is very much review at this point, and you should feel comfortable with this process.

Alright - we have plenty to work with now. Let's take a break here, and check in with our Trello board - we can now move our two tasks, C and I, to the "Done" column, and then move towards implementing our other files that we need next.


Example GitHub Repo for Jadle Code at this stage

Here are our tests for our getters and setters. This code checks the alternative constructor too.

src/test/java/models/RestaurantTest.java
public class RestaurantTest {
   @Before
   public void setUp() throws Exception {
   }

   @After
   public void tearDown() throws Exception {
   }

   @Test
   public void getNameReturnsCorrectName() throws Exception {
      Restaurant testRestaurant = setupRestaurant();
      assertEquals("Fish Witch", testRestaurant.getName());
   }

   @Test
   public void getAddressReturnsCorrectAddress() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       assertEquals("214 NE Broadway", testRestaurant.getAddress());
   }

   @Test
   public void getZipReturnsCorrectZip() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       assertEquals("97232", testRestaurant.getZipcode());
   }
   @Test
   public void getPhoneReturnsCorrectPhone() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       assertEquals("503-402-9874", testRestaurant.getPhone());
   }

   @Test
   public void getWebsiteReturnsCorrectWebsite() throws Exception {
       Restaurant testRestaurant = setupAltRestaurant();
       assertEquals("no website listed", testRestaurant.getWebsite());
   }

   @Test
   public void getEmailReturnsCorrectEmail() throws Exception {
       Restaurant testRestaurant = setupAltRestaurant();
       assertEquals("no email available", testRestaurant.getEmail());
   }

   @Test
   public void setNameSetsCorrectName() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setName("Steak House");
       assertNotEquals("Fish Witch",testRestaurant.getName());
   }

   @Test
   public void setAddressSetsCorrectAddress() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setAddress("6600 NE Ainsworth");
       assertNotEquals("214 NE Broadway", testRestaurant.getAddress());
   }

   @Test
   public void setZipSetsCorrectZip() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setZipcode("78902");
       assertNotEquals("97232", testRestaurant.getZipcode());
   }
   @Test
   public void setPhoneSetsCorrectPhone() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setPhone("971-898-7878");
       assertNotEquals("503-402-9874", testRestaurant.getPhone());
   }

   @Test
   public void setWebsiteSetsCorrectWebsite() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setWebsite("http://steakhouse.com");
       assertNotEquals("http://fishwitch.com", testRestaurant.getWebsite());
   }

   @Test
   public void setEmailSetsCorrectEmail() throws Exception {
       Restaurant testRestaurant = setupRestaurant();
       testRestaurant.setEmail("[email protected]");
       assertNotEquals("[email protected]", testRestaurant.getEmail());
   }

   public Restaurant setupRestaurant (){
       return new Restaurant("Fish Witch", "214 NE Broadway", "97232", "503-402-9874", "http://fishwitch.com", "[email protected]");

   }

   public Restaurant setupAltRestaurant (){
       return new Restaurant("Fish Witch", "214 NE Broadway", "97232", "503-402-9874");

   }
}

This is our Restaurant class:

package models;

import java.util.Objects;

public class Restaurant {
  private String name;
  private String address;
  private String zipcode;
  private String phone;
  private String website;
  private String email;
  private int id;

  public Restaurant(String name, String address, String zipcode, String phone) {
    this.name = name;
    this.address = address;
    this.zipcode = zipcode;
    this.phone = phone;
    this.website = "no website listed";
    this.email = "no email available";
  }

  public Restaurant(String name, String address, String zipcode, String phone, String website, String email) {
    this.name = name;
    this.address = address;
    this.zipcode = zipcode;
    this.phone = phone;
    this.website = website;
    this.email = email;
  }

  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;
  }

  public String getZipcode() {
    return zipcode;
  }

  public void setZipcode(String zipcode) {
    this.zipcode = zipcode;
  }

  public String getPhone() {
    return phone;
  }

  public void setPhone(String phone) {
    this.phone = phone;
  }

  public String getWebsite() {
    return website;
  }

  public void setWebsite(String website) {
    this.website = website;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

//generate the hashcode and equals - do not copy it, as it won't work correctly if any of your properties have changed.

}


See the repo link at the bottom of the lesson to check your Review.java, Foodtype.java, ReviewTest.java, and FoodtypeTest.java files.