Hibernate @Enumerated mapping

34,074

Solution 1

Check these two articles - http://community.jboss.org/wiki/Java5EnumUserType and http://community.jboss.org/wiki/UserTypeforpersistingaTypesafeEnumerationwithaVARCHARcolumn

They solve the problem by a custom UserType.

Solution 2

The best to customize mapping for enums is to use AttributeConverter i.e:

@Entity
public class Person {
    ...
    @Basic
    @Convert( converter=GenderConverter.class )
    public Gender gender;
}

public enum Gender {
    MALE( 'M' ),
    FEMALE( 'F' );

    private final char code;

    private Gender(char code) {
        this.code = code;
    }

    public char getCode() {
        return code;
    }

    public static Gender fromCode(char code) {
        if ( code == 'M' || code == 'm' ) {
            return MALE;
        }
        if ( code == 'F' || code == 'f' ) {
            return FEMALE;
        }
        throw ...
    }
}

@Converter
public class GenderConverter
        implements AttributeConverter<Gender, Character> {

    public Character convertToDatabaseColumn(Gender value) {
        if ( value == null ) {
            return null;
        }

        return value.getCode();
    }

    public Gender convertToEntityAttribute(Character value) {
        if ( value == null ) {
            return null;
        }

        return Gender.fromCode( value );
    }
}

You can find it in Hibernate docs: http://docs.jboss.org/hibernate/orm/5.0/mappingGuide/en-US/html_single/#d5e678

Solution 3

Here is an example which uses annotations.

http://www.gabiaxel.com/2011/01/better-enum-mapping-with-hibernate.html

It's still based off of a custom UserType. Four and a half years later and I'm still not aware of a better way to do this.

Typically, I persist my enum values as a char / int, some simple ID, then use a transient method that finds the appropriate enum by the simple ID value, e.g.

@Transient
public MyEnum getMyEnum() {
    return MyEnum.findById(simpleId); // 
}

and...

public enum MyEnum {
    FOO('F'),
    BAR('B');

    private char id;
    private static Map<Character, MyEnum> myEnumById = new HashMap<Character, MyEnum>();

    static {
        for (MyEnum myEnum : values()) {
            myEnumById.put(myEnum.getId(), myEnum);
        }
    }

    private MyEnum(char id) {
        this.id = id;
    }

    public static MyEnum findById(char id) {
        return myEnumById.get(id);
    }

    public char getId() {
        return id;
    }
}
Share:
34,074
saravana_pc
Author by

saravana_pc

Updated on November 08, 2020

Comments

  • saravana_pc
    saravana_pc over 3 years

    Hibernate provides @Enumerated annotation which supports two types of Enum mapping either using ORDINAL or STRING. When we map using EnumType.STRING, it takes the "name" of the Enum and not the toString() representation of the Enum. This is a problem in scenarios where the database column consists of only one character. For example, I have the following Enum:

    public enum Status{
      OPEN{
       @Override
       public String toString(){
         return "O";}
       },
    
      WAITLIST{
       @Override
       public String toString(){
         return "W";}
       },
    
      COMPLETE{
       @Override
       public String toString(){
         return "C";}
       }
    
    }
    

    When I persist the enum Status.OPEN using @Enumerated(EnumType.STRING), the value that Hibernate tries to store in the database is OPEN. However, my database column consists of only one character and hence it throws an exception.

    One way to overcome this issue is to change the Enum type to hold single characters (like STATUS.O, STATUS.W instead of STATUS.OPEN, STATUS.WAITLIST). However, this reduces readability. Any suggestions to preserve the readability as well as mapping the Enum to a single character column?

    Thanks.