4 November 2013

JPA : choose your enum ordinals (Updated)

Ordinal enums are brittle with JPA.
If you change the order of the enum constants,
the ordinal number that is saved to the database changes.

You can solve that by assigning your own code in the enum (10,20,30 in the example).
In the entity, make the enum transient.
Before saving the entity put your code in an int attribute, which will be stored in the database.
After loading convert the int back to the enum.

 Update: In JPA 2.1 you can also do this with @Converter


public enum Status{
  OPEN(10), CLOSED(20), CANCELLED(30);
  private int code;  
  
  private Status(int code) {  
    this.code = code;  
  }  
       
  public int getCode() {  
    return code;  
  }
     
  public static  Status getStatus(int code){
    for (Status stat : Status.values()) {
      if (stat.getCode()==code) return stat;
    }
    return null; // not found: invalid code
  }
}
       
@Entity
public class Auction{
  private int status;
  @Transient private Status statEnum;

  public int getStatus(){
    return status;
  }

   public void setStatus(int status){
    this.status = status;
  }

  @PostLoad private void int2enum(){
    statenum = Status.getStatus(status);
  }

  @PrePersist private void enum2int(){
    status = statEnum.getCode();
  }
  //...
}


NB: kudos to Guy for moving conversion to callbacks.