Hibernate and Enumeration
Plain Enumeration in Hibernate
Lets take a simple case of plain enumeration.Here we are creating a non parameterized enumeration for educational qualification and using it in the model class.
SQL statements
-- Database entity showing normal enum handling by hibernate create table ORM_PersonEduProfile( Id bigint Identity(1,1) not null primary key, Name varchar(50) not null, Address varchar(50) not null, EduQualification varchar(10) not null )
EduEnum.java having enumeration values for High School,Under Graduate,Post Graduate and PhD
package com.kunaal.model.plainEnum; /** * Enum for High School,UG,PG,PHD * * @author Kunaal A Trehan * */ public enum EduEnum { HS, UG, PG, PHD; }
If we have to use such plain enums in Hibernate,we just have to define @Enumerated annotation on the corresponding field.
We are going to use EduEnum in PersonEduEnum.java
PersonEduQual.java -In this class we have eduQual property mapped to EduEnum.In order to tell the hibernate that property is mapped to an enumeration.We just have to provide @Enumerated annotation
package com.kunaal.model.plainEnum; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import com.kunaal.model.BaseModel; /** * Model class showing usage of simple enumeration * @author Kunaal A Trehan * */ @Entity @Table(name="ORM_PersonEduProfile") public class PersonEduQual implements BaseModel<Long>{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Long id; @Column(name="name") private String name; @Column(name="address") private String address; @Enumerated(EnumType.STRING) @Column(name="eduQualification") private EduEnum eduQual; /** * @return the id */ public Long getId() { return id; } /** * @param id the id to set */ public void setId(Long id) { this.id = id; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the address */ public String getAddress() { return address; } /** * @param address the address to set */ public void setAddress(String address) { this.address = address; } /** * @return the eduQual */ public EduEnum getEduQual() { return eduQual; } /** * @param eduQual the eduQual to set */ public void setEduQual(EduEnum eduQual) { this.eduQual = eduQual; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PersonEduQual other = (PersonEduQual) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; } public Long getPrimaryKey() { return getId(); } }
So using plain enumeration is very simple.By providing the @Enumerated annotation,hibernate knows that it has to fetch the value from enumeration and to create an enumeration when fetching the information from database.Internally Hibernate uses an user type for doing this.
Paramterized Enumeration in Hibernate
There are some cases when we have to show different information in the UI and persist different information in the database.In that case we use parameterized enumeration.
Lets take the use case of Gender.We want to show MALE in the UI.But persist it as 'M' in the database.Similarly for FEMALE,we want to persist it as 'F' in database.Inorder to support it we create a parameterized user type.
SQL Statements:-
-- Database entity showing custom enum mapping handling by hibernate create table ORM_EnumPerson( Id bigint Identity(1,1) not null primary key, Name varchar(50) not null, Sex char(1) not null, Age int not null, DOB datetime not null, Address varchar(250) not null )
GenderEnum.java- Implementation of Parameterized enumeration
Here we are storing MALE as 'M' and FEMALE as 'F'
package com.kunaal.model.customEnum; /** * Custom enum type where UI and DB have different values * for same entity * * @author Kunaal A Trehan * */ public enum GenderEnum { MALE("M"), FEMALE("F"); /** * Private gender code */ private String genderCode; private GenderEnum(String val){ this.genderCode=val; } /** * @return the genderCode */ public String getGenderCode() { return genderCode; } /** * @param genderCode the genderCode to set */ public void setGenderCode(String genderCode) { this.genderCode = genderCode; } /** * Utility method for creating enumeration from the db represented value * * @param value * @return */ public static GenderEnum recreateEnum(String value){ GenderEnum enumVal=null; if(value !=null){ if(value.equalsIgnoreCase("M")) enumVal=GenderEnum.MALE; else if(value.equalsIgnoreCase("F")) enumVal=GenderEnum.FEMALE; } return enumVal; } /** * Utility method for inserting string value in db from enumeration * * @return */ public String recreateString(){ return genderCode; } }
EnumUserType.java-Parameterized user type for handling parameterized enum.In this user type,we pass some parameters which we use in user type for doing parameterized enumeration conversion.
In this UserType,we pass parameters like method to create enumeration,method to fetch value to persist in database and actual enumeration class which needs to be looked up for method implementations
package com.kunaal.model.customEnum; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; import org.springframework.util.ObjectUtils; import com.kunaal.model.customEnum.GenderEnum; /** * Parameterized generalized user type for enum handling * It can handle any type of enum as long db data type is * character. * We can have one more parameter and get rid of this bottleneck also * * @author Kunaal A Trehan * */ public class EnumUserType implements UserType,ParameterizedType{ private Method recreateEnumMthd; private Method recreateStringMthd; private Class enumClass; /** * This method uses the parameter values passed during enum mapping definition * and sets corresponding properties defined */ public void setParameterValues(Properties parameters) { if(parameters !=null){ String enumMthd = parameters.getProperty("recreateEnumMthd"); String strMthd=parameters.getProperty("recreateStringMthd"); String className=parameters.getProperty("enumClassName"); Class<?> returnType =null; try { enumClass=Class.forName(className); recreateStringMthd = enumClass.getMethod(strMthd, new Class[]{}); returnType = recreateStringMthd.getReturnType(); recreateEnumMthd=enumClass.getMethod(enumMthd, new Class[]{returnType}); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } /** * This method maps the database mapping */ public int[] sqlTypes() { return new int[]{Types.CHAR}; } /** * This method maps the class for which user type is created */ public Class returnedClass() { //return GenderEnum.class; return enumClass; } public boolean equals(Object x, Object y) throws HibernateException { return ObjectUtils.nullSafeEquals(x, y); } /** * Fetch the hash code */ public int hashCode(Object x) throws HibernateException { return x.hashCode(); } /** * Recreate the enum from the resultset */ public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { String value = rs.getString(names[0]); Object returnVal=null; if(value==null) return null; else{ try { returnVal = recreateEnumMthd.invoke(enumClass, new Object[]{value}); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } //return (GenderEnum)returnVal; return returnVal; } /** * Fetch the data from enum and set it in prepared statement */ public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { String prepStmtVal=null; if(value ==null){ st.setObject(index, null); }else{ try { prepStmtVal = (String)recreateStringMthd.invoke(value, new Object[]{}); st.setString(index, prepStmtVal); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } /** * Deep copy method */ public Object deepCopy(Object value) throws HibernateException { if (value==null) return null; else{ GenderEnum enumVal=(GenderEnum)value; return GenderEnum.recreateEnum(enumVal.getGenderCode()); } } public boolean isMutable() { return false; } public Serializable disassemble(Object value) throws HibernateException { Object deepCopy=deepCopy(value); if(!(deepCopy instanceof Serializable)) return (Serializable)deepCopy; return null; } public Object assemble(Serializable cached, Object owner) throws HibernateException { return deepCopy(cached); } public Object replace(Object original, Object target, Object owner) throws HibernateException { return deepCopy(original); } }
In order to use the paramterized enum and corresponding usertype in the class.We define the user type and pass the paramters.In the EnumPerson class look at the genderEnum property where we are providing this mapping.
EnumPerson.java using the paramterized enum for genderEnum property.
package com.kunaal.model.customEnum; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Type; import com.kunaal.model.BaseModel; import com.kunaal.model.customEnum.GenderEnum; /** * * Model class showing custom Enum implementation . * * @author Kunaal A Trehan * */ @Entity @Table(name="ORM_EnumPerson") public class EnumPerson implements BaseModel<Long>{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private Long personId; @Column(name="name") private String name; @Type(type="com.kunaal.model.customEnum.EnumUserType", parameters={ @Parameter(name="enumClassName",value="com.kunaal.model.customEnum.GenderEnum"), @Parameter(name="recreateEnumMthd",value="recreateEnum"), @Parameter(name="recreateStringMthd",value="recreateString") } ) @Column(name="sex") private GenderEnum genderEnum; @Column(name="age") private Integer age; @Column(name="dob") private Date dob; @Column(name="address") private String address; /** * @return the personId */ public Long getPersonId() { return personId; } /** * @param personId the personId to set */ public void setPersonId(Long personId) { this.personId = personId; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the genderEnum */ public GenderEnum getGenderEnum() { return genderEnum; } /** * @param genderEnum the genderEnum to set */ public void setGenderEnum(GenderEnum genderEnum) { this.genderEnum = genderEnum; } /** * @return the age */ public Integer getAge() { return age; } /** * @param age the age to set */ public void setAge(Integer age) { this.age = age; } /** * @return the dob */ public Date getDob() { return dob; } /** * @param dob the dob to set */ public void setDob(Date dob) { this.dob = dob; } /** * @return the address */ public String getAddress() { return address; } /** * @param address the address to set */ public void setAddress(String address) { this.address = address; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((personId == null) ? 0 : personId.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; EnumPerson other = (EnumPerson) obj; if (personId == null) { if (other.personId != null) return false; } else if (!personId.equals(other.personId)) return false; return true; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "EnumPerson [personId=" + personId + ", name=" + name + ", genderEnum=" + genderEnum + ", age=" + age + ", dob=" + dob + ", address=" + address + "]"; } public Long getPrimaryKey() { return getPersonId(); } }
Excellent post!
ReplyDeleteYou need to change the "deepCopy(Object value)" method of the EnumUserType class, because it currently contains a hard reference to "GenderEnum". This makes the EnumUserType not re-usable for other enumerations.
Really its awesome post.. :)
ReplyDeleteYou lost me at the setter within the enum
ReplyDeleteThanks for the post. Just to fill in some missing details:
ReplyDeleteFor the deepCopy method, I think you can just return the object passed in, since this UserType is for an enum, and enums are immutable.
For disassemble, you have a negation that should be removed. I just did this:
return (o instanceof Serializable) ? (Serializable) deepCopy(o) : null;
@eric m Ok, so if deepCopy retruns value (cause of enums are immutable):
Delete- assemble could just return cached
- disassemble could return (Serialized) value
- and replace could return original
What do you think guys, am I right?
Nice . very useful topic
ReplyDeleteJava Online Training Bangalore
Australia Best Tutor is one of the best Online Assignment Help providers at an affordable price. Here All Learners or Students are getting best quality assignment help with reference and styles formatting.
ReplyDeleteVisit us for more Information
Australia Best Tutor
Sydney, NSW, Australia
Call @ +61-730-407-305
Live Chat @ https://www.australiabesttutor.com
Our Services
Online assignment help Australia
my assignment help Australia
assignment help
help with assignment
Online instant assignment help
Online Assignment help Services
This is an awesome post. Really very informative and creative contents. This concept is a good way to enhance the knowledge.
ReplyDeleteLike it and help me to development very well. Thank you for this brief explanation and very nice information. Well got good knowledge.
Java Training in Gurgaon
Thanks for sharing this valuable post with us.
ReplyDeleteHibernate Training in Gurgaon
Best kitchen chimney installation and service in Faridabad
ReplyDeleteWhen cooking with oil, you will see the fact that smoke usually receives emitted in case you often uses the identical oil. Typically, these form of eating places have today's hoods as well as exhaust fans.
Visit here
Kitchen Chimney Repair Service in Noida
Kitchen Kitchen Chimney Repair Service in Vaishali
Kitchen Kitchen Chimney Repair Service in indirapuram
Kitchen Kitchen Chimney Repair Service in vasundhra
Kitchen Kitchen Chimney Repair Service in faridabad
This is an awesome post.Really very informative and creative contents. These concept is a good way to enhance the knowledge.
ReplyDeleteI like it and help me to development very well.Thank you for this brief explanation and very nice information.Well, got a good knowledge.
Java training in Indira nagar
Java training in Rajaji nagar
Java training in Marathahalli
Java training in Btm layout
Java training in Marathahalli This is an awesome post.Really very informative and creative contents. These concept is a good way to enhance the knowledge.
I like it and help me to development very well.Thank you for this brief explanation and very nice information.Well, got a good knowledge.
Java training in Indira nagar
Java training in Rajaji nagar
Java training in Marathahalli
Java training in Btm layout
Java training in Marathahalli
Thank you for your post. This is excellent information. It is amazing and wonderful to visit your site.
ReplyDeleteCEH Training In Hyderbad
Great article ...Thanks for your great information....
ReplyDeletePython Django Online Training
Python Django Training in Hyderabad
Nice post. Thank you to provide us this useful information. Victor Stone Jacket
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteGreat information about wilderness for beginners giving the opportunity for new people. yeezy gap round jacket
ReplyDeleteGrab the Oracle Training in Chennai from Infycle Technologies the best software training and placement center in Chennai which is providing technical software courses such as Data Science, Artificial Intelligence, Cyber Security, Big Data, Java, Hadoop, Selenium, Android, and iOS Development, DevOps, etc with 100% hands-on practical training.
ReplyDeleteFantastic blog i have never ever read this type of amazing information. power 50 cent jacket
ReplyDelete