Much of Java’s appeal (not to mention JSF, ORM, and GWT with a little help) is the ability to code in terms of rich domain objects such as the enumerated type. My next several blog posts will demonstrate the use of enums throughout a GAE+GWT application, beginning with persistence.
According to the AppEngine docs, Java enums are not one of the core value types, which might lead one to believe that they’re not supported. However, closer examination reveals that enums are indeed supported by DataNucleus JDO and JPA, which take care of mapping enums to Datastore core value types String (JDO + JPA) or Integer (JPA).
JDO
JDO mapping requires no special annotations and persists the enum as a String by name. One of the DataNucleus doc pages (search for “ordinal”) suggests it may be possible to persist by ordinal instead; however, I haven’t found this documented for JDO. Persistence by name is likely better, anyway, as it allows you the flexibility to add new enum values later in any ordinal position.
public enum ScheduleMethod {RANDOM, FILL, CUSTOM}; @Persistent private ScheduleMethod scheduleMethod = ScheduleMethod.RANDOM;
Note that Google does have a unit test for enum persistence in JDO.
JPA
JPA mapping requires the use of the @Enumerated annotation, which additionally lets you specify whether to map by name (String) or ordinal (Integer).
Roll-your-own
Of course, you can always roll your own mapping strategy if for some reason you need special behavior. With AppEngine Datastore, you can persist any object class by making it Serializable or Embedded, although the former has the disadvantage that you can’t use object properties in queries. You can also create a custom enum class and persist the enum by any core value type as in the example below.
public static enum Frequency { DAILY(1), WEEKLY(7), MONTHLY(30), QUARTERLY(90), YEARLY(365); private int periodDays; Frequency(int periodDays) { this.periodDays = periodDays; } public int getPeriodDays() { return periodDays; } public static Frequency getValue(int i) { for (Frequency f : Frequency.values()) { if (f.getPeriodDays() == i) return f; } throw new IllegalArgumentException("Invalid frequency period days: " + i); } } @Persistent private Integer periodDays = Frequency.WEEKLY.getPeriodDays(); /** * Convenience method to get frequency as an enum * @return Frequency */ public Frequency getFrequency() { return Frequency.getValue(this.getPeriodDays()); } public void setFrequency(Frequency f) { this.setPeriodDays(f.getPeriodDays()); }