Enumerated Types with JPA, and your Sock Drawer

2008-02-18

One feature of JPA that didn’t exist in plain-vanilla Hibernate is support for Enumerated types. I haven’t seen a lot of examples of this in practice or on the internet, so in this post I’ll show one example of how to use JDK 5 enumerations with JPA.

For our example, we are going to create an inventory system for our sock drawer. It is comprised of only two tables. The first table, called SOCK, contains one row per sock in our drawer. The columns of the table are:

  • sock_id – an auto-incrementing identity column.
  • sock_description – a varchar column for a free-form text description of the sock.
  • sock_pattern_id – a reference to a row in the SOCK_PATTERN table.

As you may have guessed, the SOCK_PATTERN table looks like this: * sock_pattern_id – an integer primary key. It’s not auto-incrementing, because we will want to have control over the contents of the field. * sock_pattern_description – a varchar column for a free-form text description of the pattern.

We need to “prime” our SOCK_PATTERN table with the valid patterns and create a foreign key relationship between the two tables:

INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (,'SOLID');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (1,'STRIPES');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (2,'POLKA_DOT');
INSERT INTO SOCK_PATTERN (sock_pattern_id,sock_pattern_description) VALUES (3,'ARGYLE');

Note that we populated sock_pattern_id starting with zero; this is important because the Enumeration below is zero-indexed.

Next, let’s create the classes:

public enum SockPattern {
 SOLID, STRIPES, POLKA_DOT, ARGYLE
}
 
@Entity @Table(name="SOCK")
public class Sock {
 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="sock_id")
 private Integer id;
 
 @Column(name="sock_description")
 private String description;
 
 @Enumerated @Column(name="sock_pattern_id")
 private SockPattern pattern;
 
 public Integer getId() { return id; }
 public void setId(Integer id) { this.id = id; }
 
 public String getDescription() { return description; }
 public void setDescription(String description) { this.description = description; }
 
 public SockPattern getPattern() { return pattern; }
 public void setPattern(SockPattern pattern) { this.pattern = pattern; }
}

Now, to use our wonderful contraption, you’d do something like the following:

public class Demo {
 private static EntityManagerFactory emf;
 static {
     Demo.emf = Persistence.createEntityManagerFactory("sockdrawer");
 }
 
 @Test
 public void socksOne() {
     Sock sock = new Sock();
     sock.setDescription("My favorite sock.");
     sock.setPattern(SockPattern.ARGYLE);
     EntityManager em = Demo.emf.createEntityManager();
     em.getTransaction().begin();
     em.persist(sock);
     em.getTransaction().commit();
     em.close();
 }
}

There are some obvious pitfalls to this approach. The object/relational mapping is very brittle; for this code to work, the IDs in the database always need to match the values that the ORM tool gets from the enumeration. Changing these values at a later date could cause some surprising results, and you can’t insert new rows without updating the Enumeration and recompiling. It does obviate the need to map the SOCK_PATTERN table, and you won’t need to worry about the details of cascading the persistent state of related Sock and SockPattern objects.

It’s just a new tool in the JPA toolbox.

(The code in this blog post was tested w/ Postgres and Toplink)

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.