-->
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.  [ 9 posts ] 
Author Message
 Post subject: Using a class as a key?
PostPosted: Thu Sep 11, 2003 4:17 pm 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
I have a conceptual problem. My java object HAS-A identity object that corresponds to the key column in the database. This identity object in turn extends from a base ID class. <ID> doesn't support the class keyword so I haven't found a satisfactory way to represent this in my hbm file.

How should I approach this? I looked at components but did not grasp how I would use that as the <ID>.

The following code shows my objects as they are, and my HBM as I conceptually want it to work...

public class BaseId
{
private String Id = "";
public BaseId(){}
protected String getValue() { return Id; }
protected void setValue(String id) { Id = id; }
}

public class NewId extends BaseId
{
public NewId(){}
public Integer getId { return new Integer(super.getValue()); }
public void setId(Integer id) { super.setValue(id.toString()); }
}

public MyObject
{
private NewId Id;

// various stuff

public NewId getId() { return Id; }
public void setId(NewId id) { Id = id; }
}

<hibernate-mapping>
<class name="MyObject" table="mytable">
<id
name="Id"
class="NewId"
column="CLASSID"
unsaved-value="-1"
/>

<!-- various stuff -->

</class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 11, 2003 4:28 pm 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
Hmm well I just saw greg's post on composite id and so I specified the class in the type field (non-orthogonal keywords!! :) ).

This seemed to work but Hibernate blew up claiming it could not serialize the object. The host and its wrapped identity object both extend from base classes that implement Serializable.

Why would the serializer fail when the base objects both implement serializable? Thanks for helping me zero in on this!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 11, 2003 5:16 pm 
Pro
Pro

Joined: Tue Aug 26, 2003 1:24 pm
Posts: 213
Location: Richardson, TX
Quote:
Thanks for helping me zero in on this!


Now, hold your horses...be a tad patient...

Are you implementing a UserType for your ID? Have you read the wiki on costom id's? http://www.hibernate.org/50.html

The class specified in the type property must implement UserType or CompositeUserType. It should NOT be the actual class that holds data. In your case, you'd have something like this:

Code:
public class NewIdType implements UserType {
...
}


Have you done this?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 11:48 am 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
Well I can see why you suggested I rein in... just for my trivial example I wound up adding four new pretty much identical classes at 75 lines each to my codebase, whose sole contribution was code bloat to work around the fact Hibernate can't reflect a property used as an Id as it can for any other attribute.

I'm sure with some refactoring I could reduce the redundancy but that doesn't change the fact that now I have more code to maintain and more opportunities to introduce defects. Hibernate is most attractive to me when I write almost no custom code to support it, otherwise I may as well go back to JDO/DAO-DTO patterns with a JCS framework.

What is the reasoning for Custom Ids? Is this perhaps overkill in my particular case? I'm simply strongly typing/refining a base identity class which just wraps a single attribute - that single attribute maps to a table's key column. In some cases a refined identity class maps to an integer column and in other cases to a string column - but the behavior for all is identical.

On top of all this Hibernate failed to map the custom type (or I failed to code it correctly, more likely!). Here is the error, and farther down the custom type:

Code:
[ERROR] Configuration - -Could not compile the mapping document <net.sf.hibernate.MappingException: Cannot instantiate custom type: com.product.persistence.hibernate.CompanyIdType>net.sf.hibernate.MappingException: Cannot instantiate custom type: com.product.persistence.hibernate.CompanyIdType
   at net.sf.hibernate.type.CustomType.<init>(CustomType.java:43)
   at net.sf.hibernate.type.TypeFactory.hueristicType(TypeFactory.java:149)
   at net.sf.hibernate.cfg.Binder.getTypeFromXML(Binder.java:787)
   at net.sf.hibernate.cfg.Binder.bindValue(Binder.java:354)
   at net.sf.hibernate.cfg.Binder.bindRootClass(Binder.java:224)
   at net.sf.hibernate.cfg.Binder.bindRoot(Binder.java:1095)
   at net.sf.hibernate.cfg.Configuration.add(Configuration.java:230)
   at net.sf.hibernate.cfg.Configuration.addInputStream(Configuration.java:252)
   at net.sf.hibernate.cfg.Configuration.addClass(Configuration.java:286)
   at com.product.persistence.hibernate.ProductPersistenceTest.<clinit>(ProductPersistenceTest.java:44)
   at com.product.persistence.hibernate.TestHibernate.main(TestHibernate.java:32)

java.lang.ExceptionInInitializerError: java.lang.RuntimeException: couldn't get connection
   at com.product.persistence.hibernate.ProductPersistenceTest.<clinit>(ProductPersistenceTest.java:54)
   at com.product.persistence.hibernate.TestHibernate.main(TestHibernate.java:32)
Exception in thread "main"


Here is the custom type - the example Greg linked appeared to have syntax errors so it's possible I introduced defect by tweaking the code.

Code:
import java.sql.*;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
import com.product.CompanyId;

public abstract class CompanyIdType
    implements UserType
{

   private static final int[] SQL_TYPES =
      new int[] { Types.VARCHAR }
      ;
   
    public int[] sqltypes() {
        return SQL_TYPES;
    }

    public boolean isMutable() {
        return false;
    }

    public Class returnedClass()
    {
        return CompanyId.class;
    }

    public boolean equals(Object x, Object y) {
        return (x==y) || ( x!=null && y!=null && x.equals(y) );
    }

    public Object deepCopy(Object value) {
        return value;
    }

    public Object nullSafeGet(
       ResultSet rs,
       String[] names,
       Object owner
       )
        throws HibernateException, SQLException
   {
      String id = rs.getString(names[0]);
        if ( rs.wasNull() ) return null;

        return new CompanyId(id);
    }

    public void nullSafeSet(
       PreparedStatement st,
       Object value,
       int index
       )
        throws HibernateException, SQLException
   {
        if (value==null) {
           st.setNull(index, Types.VARCHAR);
        }
        else {
           st.setString( index, ( (CompanyId) value ).getValue() );
        }
    }

}



And here is the HBM.

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>

    <class name="com.product.CompanyDto" table="CUBEPRDCOMPANY">

      <id
         name="Id"
         column="COMPANYID"
           type="com.product.persistence.hibernate.CompanyIdType"
      >
         <generator class="assigned"/>
      </id>
      <property
         name="Description"
         column="COMPANYDESC"
         type="string"
         length="50"
      />
      <property
         name="TotalSales"
         column="SALES"
         type="float"
      />

      <!-- FK to child Departments -->
      <set
         name="ProductDepartmentList"
         cascade="all"
         inverse="true"
         lazy="true"
      >
         <key column="COMPANYID"/>
         <one-to-many class="com.product.DepartmentDto"/>
      </set>

   </class>

</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 11:51 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I think it helps to read the documentation.

Looks like this problem is solved just perfectly using a <composite-id> mapping ... unless I'm missing something.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 11:56 am 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
Also adding more complete example of the base & extended identity classes, and the entity class that uses it.

The base identity class:

Code:
import java.io.Serializable;

public class BaseProductId
    implements Serializable
{
   // *******************************************************************
   // PRIVATE DATA MEMBERS

   public static final String Default = "-1";
   private String Id = Default;

   // *******************************************************************
   // CONSTRUCTORS

   public BaseProductId(){}
   public BaseProductId(
      String id
      )
   {
      setValue(id);
    }

   // *******************************************************************
   // PROPERTIES

   public String getValue() {
      return Id;
   }
   public void setValue(
      String id
      )
   {
      if (id == null)
         id = Default;
      if (id == "")
         id = Default;
      Id = id.trim();
   }

   // *******************************************************************
   // METHODS

   public boolean isInitialized()
   {
      if (this.Id.equals(Default))
         return false;
      else
         return true;
   }

   public boolean equals(
      Object id
      )
   {
      boolean flag = false;
      if (id instanceof BaseProductId)
      {
         BaseProductId productId = (BaseProductId)id;
         if (Id.equalsIgnoreCase(productId.getValue()))
            flag = true;
      }
      
      return flag;
   }

}



The refined identity class:

Code:
public class CompanyId
   extends BaseProductId
{
   public CompanyId(){}
   public CompanyId(
      Integer companyId
      )
   {
      setId(companyId);
   }
   public CompanyId(
      String companyId
      )
   {
      setId(companyId);
   }
   
   public String getId()
   {
      return super.getValue();
   }
   public void setId(String companyId)
   {
      this.setId(
         new Integer(companyId)
         );
   }
   public void setId(Integer companyId)
   {
      super.setValue(companyId.toString());
   }

   public boolean equals(
      Object id
      )
   {
      boolean flag = false;
      if (id instanceof CompanyId)
      {
         CompanyId productId = (CompanyId)id;
         if (getId().equalsIgnoreCase(productId.getValue()))
            flag = true;
      }
      
      return flag;
   }

}


The entity class:

Code:
public class CompanyDto
    extends BaseProductDto
{
   // *******************************************************************
   // PRIVATE DATA MEMBERS
   private String companyId;
   private Set m_ProductList;

   // *******************************************************************
   // CONSTRUCTORS
   public CompanyDto(){}

   public CompanyDto(
      String companyId,
      String desc
      )
   {
      setId(companyId);
      setDescription(desc);
   }

   public CompanyDto(
      String companyId,
      String desc,
      Float totalSales
      )
   {
      setId(companyId);
      setDescription(desc);
      setTotalSales(totalSales);
   }

   public CompanyDto(
      String companyId,
      String desc,
      String totalSales
      )
   {
      setId(companyId);
      setDescription(desc);
      setTotalSales(totalSales);
   }


   // *******************************************************************
   // PROPERTIES

   public String getId() {
      return companyId;
   }
   public void setId(
      String compId
      )
   {
      companyId = compId;
   }


   public Set getProductDepartmentList() {
      return m_ProductList;
   }
   public void setProductDepartmentList(Set list) {
      m_ProductList = list;
   }

   // *******************************************************************
   // METHODS

}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 11:57 am 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
gavin wrote:
I think it helps to read the documentation.

Looks like this problem is solved just perfectly using a <composite-id> mapping ... unless I'm missing something.


Okies - reading up on it now.

Why is the custom type failing?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 12:08 pm 
Newbie

Joined: Fri Sep 05, 2003 10:30 am
Posts: 17
Location: Texas
Composite Id does seem to be what's working - certainly beats extra java. I'm still running into a problems loading it but that is definitely learning curve. Thank you all for your time and help! :-)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 12, 2003 12:13 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Quote:
Why is the custom type failing?



Its an abstract class, so Hibernate can't instantiate it.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.