-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Java 1.4, Enumeration mapping
PostPosted: Tue Jul 19, 2005 7:05 am 
Newbie

Joined: Tue Jul 19, 2005 6:39 am
Posts: 4
Location: Venice, Italy
After reading the material about Java 1.5 enum and Hibernate UserType http://www.hibernate.org/272.html I did the following to use that concepts in java 1.4.

I defined an abstract enumeration class:

Code:
public abstract class AbstractEnum implements Serializable {
   
   private String id;
   private transient String value;

   /**
    * @param id
    * @param value
    */
   protected AbstractEnum(String id, String value) {
      this.id = id;
      this.value = value;
   }
   
    /**
    * @return Returns the id.
    */
   public String getId() {
      return id;
   }

   /**
    * @return Returns the value.
    */
   public String getValue() {
      return value;
   }
   
    public boolean equals(Object other) {
        return this == other;
    }
   
    public int hashCode() {
        return System.identityHashCode(id);
    }
   
    public String toString() {
        return value;
    }

}


and its implementation:
Code:
public class NumberEnum extends AbstractEnum {
   
    public static final String ONE = "1";
    public static final String TWO = "2";
    
    public static final NumberEnum ONE_LITERAL = new NumberEnum(ONE, "One");
    public static final NumberEnum TWO_LITERAL = new NumberEnum(TWO, "Two");

   /**
    * @param id
    * @param value
    */
   private NumberEnum(String id, String value) {
      super(id, value);
   }
   
   public static NumberEnum fromString(String id) {
      if (ONE.equals(id)) {
         return ONE_LITERAL;
      } else if (TWO.equals(id)) {
         return TWO_LITERAL;
      } else {
         return null;
      }
   }

   private Object resolveObject() {
      return fromString(getId());
   }

}


then, I defined the EnumUserType class as explained in the article:

Code:
public class EnumUserType implements EnhancedUserType, ParameterizedType {

   private Class enumClass;
   private Method fromString;

   /* (non-Javadoc)
    * @see org.hibernate.usertype.EnhancedUserType#objectToSQLString(java.lang.Object)
    */
   public String objectToSQLString(Object value) {
          return '\'' + idOf(value) + '\'';
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.EnhancedUserType#toXMLString(java.lang.Object)
    */
   public String toXMLString(Object value) {
      return idOf(value);
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.EnhancedUserType#fromXMLString(java.lang.String)
    */
   public Object fromXMLString(String xmlValue) {
      return valueOf(xmlValue);
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#sqlTypes()
    */
   public int[] sqlTypes() {
      return new int[] { Types.VARCHAR };
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#returnedClass()
    */
   public Class returnedClass() {
      return enumClass;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
    */
   public boolean equals(Object x, Object y) throws HibernateException {
      return x == y;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
    */
   public int hashCode(Object x) throws HibernateException {
      return x.hashCode();
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
    */
   public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
         throws HibernateException, SQLException {
        String name = rs.getString( names[0] );
        return rs.wasNull() ? null : valueOf(name);
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
    */
   public void nullSafeSet(PreparedStatement st, Object value, int index)
         throws HibernateException, SQLException {
      if (value == null) {
         st.setNull(index, Types.VARCHAR);
      } else {
         st.setString(index, idOf(value));
      }
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
    */
   public Object deepCopy(Object value) throws HibernateException {
      return value;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#isMutable()
    */
   public boolean isMutable() {
      return false;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
    */
   public Serializable disassemble(Object value) throws HibernateException {
      return (Serializable)value;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
    */
   public Object assemble(Serializable cached, Object owner)
         throws HibernateException {
      return cached;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
    */
   public Object replace(Object original, Object target, Object owner)
         throws HibernateException {
      return original;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties)
    */
   public void setParameterValues(Properties parameters) {
        String enumClassName = parameters.getProperty("enumClassName");
        try {
            enumClass = Class.forName(enumClassName);
         fromString = enumClass.getMethod("fromString", new Class[] {String.class});
         if (!AbstractEnum.class.isAssignableFrom(enumClass)) {
               throw new HibernateException("Enum class <" + enumClassName + "> does not extend AbstractEnum class.");
         }
        } catch (ClassNotFoundException cnfe) {
            throw new HibernateException("Enum class <" + enumClassName + "> not found: ", cnfe);
      } catch (NoSuchMethodException nsme) {
            throw new HibernateException("Enum class <" + enumClassName + "> does not contain formString method: ", nsme);
        }
        try {
           enumClass.getDeclaredMethod("resolveObject", new Class[0]);
      } catch (NoSuchMethodException nsme) {
            throw new HibernateException("Enum class <" + enumClassName + "> does not contain resolveObject method: ");
        }
   }
   
   private String idOf(Object value) {
      return ((AbstractEnum)value).getId();
   }
   
   private Object valueOf(String id) {
      try {
         return fromString.invoke(null, new Object[] {id});
      } catch (IllegalAccessException e) {
            throw new HibernateException("Illegal access to method fromString from class <" + enumClass.getName() + ">: ", e);
      } catch (InvocationTargetException e) {
            throw new HibernateException("Could not invoke method fromString from class <" + enumClass.getName() + ">: ", e);
      }
   }

}


I used these on this sample hbm file:
Code:
<?xml version="1.0" encoding="ASCII"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.foo.bar.test">
  <class name="TestEnum" table="testEnum">
    <id column="id" name="id" type="long">
      <generator class="native"/>
    </id>
    <property column="test_enum" length="1" name="testEnum">
      <type name="com.previnet.hibernate.usertypes.EnumUserType">
        <param name="enumClassName">com.foo.bar.test.NumberEnum</param>
      </type>
    </property>
  </class>
</hibernate-mapping>


Generating the java code with the Hibernate Tools Eclipse plugin I obtained the following:
Code:
public class TestEnum  implements java.io.Serializable {

    // Fields   

     private Long id;
     private NumberEnum testEnum;


    // Constructors

    /** default constructor */
    public TestEnum() {
    }
   
    /** constructor with id */
    public TestEnum(Long id) {
        this.id = id;
    }
   
   
   

    // Property accessors

    /**
     *
     */
    public Long getId() {
        return this.id;
    }
   
    public void setId(Long id) {
        this.id = id;
    }

    /**
     *
     */
    public NumberEnum getTestEnum() {
        return this.testEnum;
    }
   
    public void setTestEnum(NumberEnum testEnum) {
        this.testEnum = testEnum;
    }



}


I hope this can help somebody.
Cheers
Adriano


Top
 Profile  
 
 Post subject: Re: Java 1.4, Enumeration mapping
PostPosted: Mon Aug 02, 2010 11:57 am 
Beginner
Beginner

Joined: Sat Sep 17, 2005 6:50 am
Posts: 23
Finally org.hibernate.type.EnumType was included into hibernate-core from v3.6.0.Beta1 and thus enumeration mapping became very simple. Usage:

Code:
<property name="countryCode">
  <type name="org.hibernate.type.EnumType">
    <param name="enumClass">org.mycompany.CountryCode</param>
    <param name="type">1</param> <!-- should be integer from java.sql.Types constants; set to java.sql.Types.CHAR to enable mapping by enum name -->
  </type>
</property>


Top
 Profile  
 
 Post subject: Re: Java 1.4, Enumeration mapping
PostPosted: Thu Sep 23, 2010 6:33 am 
Senior
Senior

Joined: Fri May 08, 2009 12:27 pm
Posts: 168
Note that the Enum-for-Hibernate code floating in the net is intended for the case where the encoding derives directly from the Enum, either by ordinal number or by Java name.
It does not apply for database fields that are encoded as shorthand strings. E.g. CreditCardType may be encoded as "V" for VISA, "M" for MasterCard, and "E" for EC.

I'm handling this use case via a generic FiniteDomainUserType<JAVATYPE, DBTYPE>. It uses a Map<JAVATYPE, DBTYPE> to translate from Java values to database values, and a Map<DBTYPE, JAVATYPE>. The nice thing about this is that it works for arbitrary Java types, i.e. Enums and java.lang.Boolean. (The downside is that it doesn't handle boolean, because Java generics don't work with non-reference types.)
I can't publish the code, but writing it was straightforward.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.