Enums in Model Classes

One application of enum types is to represent categories of objects. We will take this approach in our coding-events application to categorize events based on their type, such as conference or meetup.

Enum Types in Models - Video

Note

The starter code for this video is found at the display-errors branch of the CodingEventsJava repo. The final code presented in this video is found on the enums branch . As always, code along to the videos on your own codingevents project.

As mentioned in the previous chapter , your display-errors constructor might contain a small quirk. If your constructor assigns non-sequential id values, this is still OK!

Enum Types in Models - Text

Create an Enum Class

In your models package within codingevents, create a new class called EventType. Before you finish entering the name of your file, select the Enum option from the list of types.

Enum type selection. Enum type selection.

Because enum values are constants, we use naming-conventions and write them in all caps. Each value is demarcated with a comma and the list is completed with a semicolon.

EventType:

1
2
3
4
5
6
7
8
public enum EventType {

   CONFERENCE,
   MEETUP,
   WORKSHOP,
   SOCIAL;

}

Add an Enum Field

Enums can store additional information affiliated with each value in fields. Enum fields are treated like fields on any other type. Again, because enum values are constants, fields should be final variables, since they will not change.

To add a displayName field to EventType, we declare the field, add a constructor, and tack on a getter method:

1
2
3
4
5
6
7
8
9
private final String displayName;

EventType(String displayName) {
   this.displayName = displayName;
}

public String getDisplayName() {
   return displayName;
}

To define the display name for each of the EventType values, we can call the constructor we just wrote like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public enum EventType {

   CONFERENCE("Conference"),
   MEETUP("Meetup"),
   WORKSHOP("Workshop"),
   SOCIAL("Social");

   private final String displayName;

   EventType(String displayName) {
      this.displayName = displayName;
   }

   public String getDisplayName() {
      return displayName;
   }

}

Add an Enum Property to a Model Class

Other objects can have enum type properties. To add an EventType property to our model Event, we create a type field in Event amongst the other fields declared:

// other Event field declarations

private EventType type;

// Event methods

We’ll want to also add this field to the Event constructor, as well as a getter and setter method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private EventType type;

public Event(String name, String description, String contactEmail, EventType type) {
   this();
   this.name = name;
   this.description = description;
   this.contactEmail = contactEmail;
   this.type = type;
}

public EventType getType() {
   return type;
}

public void setType(EventType type) {
   this.type = type;
}

Pass Enum Values Through the Controller

codingevents uses model binding to create an Event object. So like any other field on the model, the controller does not necessarily need to know about the addition of Event.type in order to create an Event instance from a form. However, we want the user to choose from the pre-defined event type values when creating their event. To do this, we’ll use the controller method displayCreateEventForm to pass those values into the view.

In EventController:

1
2
3
4
5
6
7
@GetMapping("create")
public String displayCreateEventForm(Model model) {
   model.addAttribute("title", "Create Event");
   model.addAttribute(new Event());
   model.addAttribute("types", EventType.values());
   return "events/create";
}

.values() is a built-in static method that returns an array of values defined in the given enum, in the order in which they have been declared.

With the template variable types now defined, we can use our EventType values in the view.

Use Enum Value in a Select Element

The list of constants returned from EventType lends itself well to a select-type form input. We’ll update our form so that a user will have the option to choose one of the provided event types from a dropdown menu.

In templates/events/create.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div class="form-group">
   <label> Type
   <select th:field="${event.type}">
      <option th:each="type : ${types}"
               th:value="${type}"
               th:text="${type.displayName}"
      ></option>
   </select>
   </label>
</div>

As with the other form inputs on the page, the th:field attribute determines the name and id attributes for the select tag. We make an option tag for each of the EventType values, making use of the types variable we passed in from the controller in the previous step . We set the value attribute for the model data to be the EventType value using th:value. And the type name shown to the user of the form as the displayName of the type, using th:text.

Use Enum Properties to Display Information

Once an event is created, to display its type field in the table of all events, we’ll modify templates/events/index.html to include another column:

<!-- other table headers -->
<th>Type</th>
<!-- other event data -->
<td th:text="${event.type.displayName}"</td>

In this case, the type displayed is the value of the event object’s type field, so the controller method responsible for rendering this view does not need a types variable passed in. To show the more user-friendly view of the type value, we use the .displayName field of EventType.

Check Your Understanding

Question

When we add a field to the EventType enum from codingevents, what is the strongest reason why we don’t we write a setter method for that field?

  1. Enum classes cannot contain setter methods
  2. Final variables cannot be reassigned
  3. Enum fields cannot be reassigned
  4. We don’t use a setter method in the rest of the application
Question

In coding-events, say we change our template variable name in EventController.displayCreateEventForm so that EventType.values() is now assigned to a variable, categories. Which of the template expressions in the following code block from create.html, if any, should be changed to reflect this update? Select all that apply.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div class="form-group">
   <label> Type
   <select th:field="${event.type}">
      <option th:each="type : ${types}"
               th:value="${type}"
               th:text="${type.displayName}"
      ></option>
   </select>
   </label>
</div>
  1. In line 3, ${event.type} should be changed to ${event.category}
  2. In line 4, type : ${types} should be changed to category : ${categories}
  3. In line 5, ${type} should be changed to ${category}
  4. In line 6, ${type.displayName} should be changed to ${category.displayName}