-->
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.  [ 4 posts ] 
Author Message
 Post subject: Mapping of usertype as part of a composite primary key
PostPosted: Fri May 13, 2005 11:54 am 
Newbie

Joined: Fri May 13, 2005 11:02 am
Posts: 4
I have made a usertype to map a VARCHAR column to a Calendar object, and it's working perfectly using the following mapping definition:
Code:
<property name="activeFrom">
   <column name="ActiveFrom"/>
   <type name="no.bekk.mobiletimekeeper.customtypes.CalendarStringType"/>
</property>

But when I try to use this usertype as part of a composite primary key like this:
Code:
<composite-id>
   <key-many-to-one name="project" class="Project" column="ProjectID"/>
   <key-many-to-one name="employee" class="Employee" column="EmployeeID"/>
   <key-property name="date"
      column="ActualDate"
      type="no.bekk.mobiletimekeeper.CalendarStringType">
   </key-property>
</composite-id>
I get the following exception:
Quote:
org.hibernate.MappingException: Could not determine type for: no.bekk.mobiletimekeeper.CalendarStringType, for columns: [org.hibernate.mapping.Column(ActualDate)]
org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:265)
org.hibernate.mapping.Property.getType(Property.java:47)
org.hibernate.mapping.Component.getType(Component.java:149)
org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:252)
org.hibernate.mapping.RootClass.validate(RootClass.java:189)
org.hibernate.cfg.Configuration.validate(Configuration.java:816)
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1050)
no.bekk.mobiletimekeeper.DatabaseConnection.currentSession(DatabaseConnection.java:38)
no.bekk.mobiletimekeeper.DatabaseConnection.getSortedList(DatabaseConnection.java:58)
no.bekk.mobiletimekeeper.Employees.<init>(Employees.java:26)
no.bekk.mobiletimekeeper.MtsServlet.doGet(MtsServlet.java:44)
javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

My usertype CalendarStringType looks like this:
Code:
public class CalendarStringType implements UserType
{
  private static final int[] SQL_TYPES = {Types.VARCHAR};
 
  public CalendarStringType() {}
 
  public int[] sqlTypes()
  {
    return SQL_TYPES;
  }

  /**
   * Tells Hibernate what Java type is mapped by this UserType.
   * @return The Java type which is mapped by this UserType   
   */
  public Class returnedClass()
  {
    return GregorianCalendar.class;
  }

  /**
   * The UserType is responsible for dirty-checking property values. The equals()
   * method compares the current property value to a previous snapshot and determines
   * whether the property is dirty and must by saved to the database.
   */
  public boolean equals( Object x, Object y ) throws HibernateException
  {
    if( x != null && y != null)
      return ((GregorianCalendar)x).equals( (GregorianCalendar)y );
    return false;
  }

  /**
   * @return the objects hashcode
   */
  public int hashCode( Object x ) throws HibernateException
  {
    return ((GregorianCalendar)x).hashCode();
  }

  /**
   * retrieves the property value from the JDBC ResultSet.
   */
  public Object nullSafeGet( ResultSet resultSet, String[] names, Object owner )
     throws HibernateException, SQLException
  {
    if (resultSet.wasNull())
      return null;
   
    //The true/false value is stored in the database as tinyint.
    String dateString = resultSet.getString( names[0] );
   
    //returning a new Calendar object whoose value is set according to the value
    //of the String date. In short: parsing the retrieved string and makes a new
    //Calendar objects
    return parseDateString( dateString );
   
  }

  /**
   * writes the property value to the JDBC PreparedStatement
   */
  public void nullSafeSet( PreparedStatement prepStatement, Object value, int index )
     throws HibernateException, SQLException
  {
    if (value == null)
    {
      prepStatement.setNull( index, Types.VARCHAR );
    }
    else
    {
      String year = ((GregorianCalendar)value).get( Calendar.YEAR ) + "";
      String month = Toolbox.twoDigits( ((GregorianCalendar)value).get( Calendar.MONTH ) );
      String date = Toolbox.twoDigits( ((GregorianCalendar)value).get( Calendar.DATE ) );
     
      //perform a conversion to get Hibernate to store an appropriate VARCHAR value
      //from the String object.
      prepStatement.setString( index, year + month + date );
     
    }
  }

  /* (non-Javadoc)
   * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
   */
  public Object deepCopy( Object value ) throws HibernateException
  {
    //extract the date parameters
    int year = ((GregorianCalendar)value).get( Calendar.YEAR );
    int month = ((GregorianCalendar)value).get( Calendar.MONTH );
    int date = ((GregorianCalendar)value).get( Calendar.DATE );
   
    return new GregorianCalendar( year, month, date );
  }

  /**
   * The Java type Calendar is mutable (the type's contents can be changed after instanciation),
   * hence this method will return true.
   * @return will always return true.
   */
  public boolean isMutable()
  {
    return true;
  }

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

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

  /* (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 null;
  }
 
  /**
   * A helper method to do the parsing from a YYYYMMDD-formatted String
   * to a Java Calendar object.
   * @param toBeParsed The String to parse. It must be in the format YYYYMMDD
   * @param calendar the Calendar object that shall recieve the date parameters from the parsed
   *                 String
   * @throws NumberFormatException If the String toBeParsed isn't correctly formatted, this
   *                               exception is thrown.
   */
  private Calendar parseDateString( String toBeParsed ) throws NumberFormatException
  {
    //instanciate a new Calendar object
    GregorianCalendar calendar = new GregorianCalendar();
     
    if( toBeParsed.length() == 8 )
    {
      //extract the year, month and day from the recieved string
      int year = Integer.parseInt( toBeParsed.substring(0,4) );
      int month = Integer.parseInt( toBeParsed.substring(4,6) ) - 1; //subtract 1, months are from 0 to 11
      int day = Integer.parseInt( toBeParsed.substring(6,8) );

      //store the date
      calendar.set(year, month, day);
      return calendar;
    }
    else
    {
      throw new NumberFormatException("The date string must have the exact " +
        "length of 8. It must also only contain digits.\nDebug info:\n" +
        "String toBeParsed = " + toBeParsed );
    }
  }

}

I hope I have provided enough information for anyone to shed some light on what I should investigate on, but please ask for anything missing required to perhaps solve this problem. I'm using MySQL and Hibernate 3.0.3.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 13, 2005 1:40 pm 
Newbie

Joined: Fri May 13, 2005 11:02 am
Posts: 4
I think it might be a problem with my UserType implementation. I tried to change my getter/setter to return/accept a String which internally gets converted to and from Calendar. That makes this mapping work:
Code:
<key-property name="date" column="ActualDate"/>
as part of the composite primary key. It's a temporary workaround until I solve this problem. I would still appreciate if someone could help me review the CalendarStringType code. I'm having a bit trouble finding detailed information about defining user types. So far I've relied on the free 6th chapter from Hibernate in Action.

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 13, 2005 6:03 pm 
Expert
Expert

Joined: Sat Jun 12, 2004 4:49 pm
Posts: 915
you set for first mapping
no.bekk.mobiletimekeeper.customtypes.CalendarStringType
but another
no.bekk.mobiletimekeeper.CalendarStringType

regards


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 13, 2005 7:12 pm 
Newbie

Joined: Fri May 13, 2005 11:02 am
Posts: 4
Duh.... I was only testing you, you know...
No really! What probably took you about 5 mins to see, I have been strugling with for a whole day. This is rather embarassing... Sometimes I don't see the forrest for all the trees. Thanks for your help, and sorry for bothering with such a trivial issue. Though, it might not be the last you hear from me since I've just started on trying to map a many-to-many relation to a TreeSet. *shriver*


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.