-->
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: composite-id problem with many to many associations
PostPosted: Thu May 22, 2008 3:32 pm 
Newbie

Joined: Wed Apr 30, 2008 1:49 pm
Posts: 7
Hi,

I am trying to perform a simple example for a many to many association.
My two classes are Zone and ZoneSet and the class representing the association is ZoneToZoneSet.
As advised in the book "Java persistence with Hibernate", I am using a composite id for the association table (ZoneToZoneSet) id. The ZoneToZoneSet class then declares an inner class to handle the composite id. The composite id is of course made up of the id from ZoneSet and the id from Zone.
When using a composite id, one should not specify getter and setter methods for the id since hibernate gets the values directly.
However when I do not specify accessors for the id, I get the following error at run time: (Hibernate 3.2.5 ga), which indicates that a getter is needed:

Code:
org.hibernate.PropertyNotFoundException: Could not find a getter for id in class test.ZoneToZoneSet
   at org.hibernate.property.BasicPropertyAccessor.createGetter(BasicPropertyAccessor.java:282)
   at org.hibernate.property.BasicPropertyAccessor.getGetter(BasicPropertyAccessor.java:275)
   at org.hibernate.tuple.PropertyFactory.getGetter(PropertyFactory.java:168)
   at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:44)
   at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:123)
   at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:434)
   at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:109)
   at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:55)
   at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226)
   at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
   at test.Tester.getSessionFactory(Tester.java:35)
   at test.Tester.testZones(Tester.java:41)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at junit.framework.TestCase.runTest(TestCase.java:154)
   at junit.framework.TestCase.runBare(TestCase.java:127)
   at junit.framework.TestResult$1.protect(TestResult.java:106)
   at junit.framework.TestResult.runProtected(TestResult.java:124)
   at junit.framework.TestResult.run(TestResult.java:109)
   at junit.framework.TestCase.run(TestCase.java:118)
   at junit.framework.TestSuite.runTest(TestSuite.java:208)
   at junit.framework.TestSuite.run(TestSuite.java:203)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


This in itself suggests that there is a problem with my mappings / classes.
If I ignore this and implement dummy accessors for the id, I get one step further but I then get the following error :

Code:
java.lang.ClassCastException: java.lang.String
   at org.hibernate.type.ComponentType.toLoggableString(ComponentType.java:377)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:112)
   at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38)
   at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:618)
   at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:592)
   at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:596)
   at test.Tester.testZones(Tester.java:54)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at junit.framework.TestCase.runTest(TestCase.java:154)
   at junit.framework.TestCase.runBare(TestCase.java:127)
   at junit.framework.TestResult$1.protect(TestResult.java:106)
   at junit.framework.TestResult.runProtected(TestResult.java:124)
   at junit.framework.TestResult.run(TestResult.java:109)
   at junit.framework.TestCase.run(TestCase.java:118)
   at junit.framework.TestSuite.runTest(TestSuite.java:208)
   at junit.framework.TestSuite.run(TestSuite.java:203)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


I don't believe that the second error is too significant as it is only there as a result of the first one.

Any help would be much appreciated.

Below is the code for my project:

ZoneToZoneSet.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 23-Apr-2008 15:18:30 by Hibernate Tools 3.2.0.CR1 -->
<hibernate-mapping>
   <class name="test.ZoneToZoneSet" table = "TSGZoneToZoneSet">
      
      <composite-id name="id" class="test.ZoneToZoneSet$Id">
         <key-property name="zoneSetId"
            access="field"
            column="ZONESET_ID"
            length="32"
            type="string"/>            
         <key-property name="zoneId"
            access="field"
            column="ZONE_ID"
            length="32"
            type="string"/>            
      </composite-id>
      

      <many-to-one name="zoneSet"
         column="ZONESET_ID"
         not-null="true"
         insert="false"
         update="false"/>
      
      <many-to-one name="zone"
         column="ZONE_ID"
         not-null="true"
         insert="false"
         update="false"/>
         

   </class>
</hibernate-mapping>


ZoneSet.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 23-Apr-2008 15:18:30 by Hibernate Tools 3.2.0.CR1 -->
<hibernate-mapping>
   <class name="test.ZoneSet" table = "TSGZoneSet">
      <id name="id" >
         <column name="id" length="32" />
         <generator class="uuid.hex" />
      </id>
            
      <property name="label" >
         <column name="LABEL" length="128" />
      </property>


      <bag name="zonesToZoneSets" inverse="true" >
         <key column="ZONESET_ID" />
         <one-to-many class="test.ZoneToZoneSet" />
      </bag>   


   </class>
</hibernate-mapping>


Zone.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 23-Apr-2008 15:18:30 by Hibernate Tools 3.2.0.CR1 -->
<hibernate-mapping>
   <class name="test.Zone" table = "TSGZone">
      <id name="id" >
         <column name="id" length="32" />
         <generator class="uuid.hex" />
      </id>
            
      <property name="label" >
         <column name="LABEL" length="128" />
      </property>

      <bag name="zonesToZoneSets" inverse="true" >
         <key column="ZONE_ID" />
         <one-to-many class="test.ZoneToZoneSet" />
      </bag>   

   </class>
</hibernate-mapping>



ZoneToZoneSet.java
Code:
package test;

import java.io.Serializable;

public class ZoneToZoneSet {

   @SuppressWarnings("serial")   
   public static class Id implements Serializable {

      private String zoneSetId;
      private String zoneId;
      
      public Id() {}
      
      public Id(String zoneSetId, String zoneId) {
         this.zoneSetId = zoneSetId;
         this.zoneId = zoneId;
      }
      
      public boolean equals(Object o) {
         if (o != null && o instanceof Id) {
            Id that = (Id)o;
            return this.zoneId.equals(that.zoneId) &&
            this.zoneSetId.equals(that.zoneSetId);
         } else {
            return false;
         }
      }
      
      public int hashCode() {
         return zoneSetId.hashCode() + zoneId.hashCode();
      }
   }
   
   /**
    * The Composite Id object
    */      
   protected Id id = new Id();   
   
   
   public String getId (){
      return "someID";
   }

   public void setId (String id){
   
   }
   
   
   public ZoneToZoneSet() {
      //id = new Id();
   }
   
   public ZoneToZoneSet(ZoneSet zoneSet, Zone zone) {
      
      this();
      
      // Set fields
      this.zoneSet = zoneSet;
      this.zone = zone;
      
      // Set identifier values
      ((Id)this.id).zoneSetId = zoneSet.getId();
      ((Id)this.id).zoneId = zone.getId();
      
      // Guarantee referential integrity      
      zoneSet.getZonesToZoneSets().add(this);
      zone.getZonesToZoneSets().add(this);
   }   
   

   /**
    */
   private ZoneSet zoneSet;

   /**
    * Getter of the property <tt>zoneSet</tt>
    * @return  Returns the zoneSet.

    */
   public ZoneSet getZoneSet() {
      return zoneSet;
   }

   /**
    * Setter of the property <tt>zoneSet</tt>
    * @param zoneSet  The zoneSet to set.
    */
   public void setZoneSet(ZoneSet zoneSet) {
      this.zoneSet = zoneSet;
   }

   /**
    */
   private Zone zone = null;

   /**
    * Getter of the property <tt>zone</tt>
    * @return  Returns the zone.

    */
   public Zone getZone() {
      return zone;
   }

   /**
    * Setter of the property <tt>zone</tt>
    * @param zone  The zone to set.
    */
   public void setZone(Zone zone) {
      this.zone = zone;
   }

}



ZoneSet.java
Code:
package test;

import java.util.List;



public class ZoneSet  {


   /**

    */
   private String id = null;

   /**
    * Getter of the property <tt>id</tt>

    */
   public String getId() {
      return id;
   }

   /**
    * Setter of the property <tt>id</tt>
    * @param id  The id to set.
    */
   protected void setId(String id) {
      this.id = id;
   }   
   
   /**
    */
   private String label = null;

   /**
    * Getter of the property <tt>name</tt>
    * @return  Returns the name.
    */
   public String getLabel() {
      return label;
   }

   /**
    * Setter of the property <tt>name</tt>
    * @param name  The name to set.
    */
   public void setLabel(String label) {
      this.label = label;
   }

   /**
    */
   private List<ZoneToZoneSet> zonesToZoneSets = new java.util.ArrayList<ZoneToZoneSet>();

   /**
    * Getter of the property <tt>zonesToZoneSets</tt>
    * @return  Returns the zonesToZoneSets.
    */
   public List<ZoneToZoneSet> getZonesToZoneSets() {
      return zonesToZoneSets;
   }

   /**
    * Setter of the property <tt>zonesToZoneSets</tt>
    * @param zonesToZoneSets  The zonesToZoneSets to set.
    */
   public void setZonesToZoneSets(List<ZoneToZoneSet> zonesToZoneSets) {
      this.zonesToZoneSets = zonesToZoneSets;
   }

}


Zone.java
Code:
package test;

import java.util.List;



public class Zone  {


   /**
    */
   private String id = null;

   /**
    * Getter of the property <tt>id</tt>
    * @return  Returns the id.
    */
   public String getId() {
      return id;
   }

   /**
    * Setter of the property <tt>id</tt>
    * @param id  The id to set.
    */
   protected void setId(String id) {
      this.id = id;
   }
   
   /**
    */
   private String label = null;

   /**
    * Getter of the property <tt>name</tt>
    * @return  Returns the name.
    */
   public String getLabel() {
      return label;
   }

   /**
    * Setter of the property <tt>name</tt>
    * @param name  The name to set.
    */
   public void setLabel(String label) {
      this.label = label;
   }


   /**
    */
   private List<ZoneToZoneSet> zonesToZoneSets = new java.util.ArrayList<ZoneToZoneSet>();

   /**
    * Getter of the property <tt>zonesToZoneSets</tt>
    * @return  Returns the zonesToZoneSets.
    */
   public List<ZoneToZoneSet> getZonesToZoneSets() {
      return zonesToZoneSets;
   }

   /**
    * Setter of the property <tt>zonesToZoneSets</tt>
    * @param zonesToZoneSets  The zonesToZoneSets to set.
    */
   public void setZonesToZoneSets(List<ZoneToZoneSet> zonesToZoneSets) {
      this.zonesToZoneSets = zonesToZoneSets;
   }

}


And finally the Tester:
Tester.java

Code:
package test;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;


public class Tester extends TestCase {

   private static SessionFactory factory= null;

   private SessionFactory getSessionFactory (){
      
      if (factory != null)
         return factory;
      
      Properties props = new Properties ();
      try {
         InputStream is = this.getClass().getResourceAsStream("hibernate.properties");
         props.load(is);
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      
      SessionFactory sessionFactory = new Configuration().addProperties(props).configure().buildSessionFactory();
      return sessionFactory;
   }   
      
   public void testZones (){
   
      Session session = getSessionFactory ().openSession();
      Transaction tx = session.beginTransaction();
      
      
      Zone zone = new Zone ();
      session.persist(zone);
   
      ZoneSet zoneSet = new ZoneSet ();   
      session.persist(zoneSet);            
   

      
      ZoneToZoneSet zoneToZoneSet = new ZoneToZoneSet(zoneSet,zone);   
      session.persist(zoneToZoneSet);
      

      tx.commit();
      session.close();   

   }
   
}


Top
 Profile  
 
 Post subject: re:composite-id problem with many to many associations
PostPosted: Thu May 22, 2008 4:37 pm 
Beginner
Beginner

Joined: Fri Jun 29, 2007 11:12 am
Posts: 25
Hello Dave,
i use getters and setters for intermidiate entitie's static id class, and never paid any attention to why i should not have it there, i always do. Your code is by the book. Did you try to debug? Also your setter for id seems to be empty.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 23, 2008 10:58 am 
Newbie

Joined: Wed Apr 30, 2008 1:49 pm
Posts: 7
I got it at last ...
The previous error:

Code:
java.lang.ClassCastException: java.lang.String  at org.hibernate.type.ComponentType.toLoggableString(ComponentType.java:377)


Was actually due to a hibernate bug that appears in some circumstances:
http://opensource.atlassian.com/project ... e/HHH-3148

Once I worked around that bug , the real error message appeared:

Code:
org.hibernate.PropertyAccessException: could not get a field value by reflection getter of test.ZoneToZoneSet$Id.zoneSetId
   at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:35)
   at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:64)
   at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:70)
   at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:86)
   at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:353)
   at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:184)
   at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:104)
   at org.hibernate.engine.EntityKey.<init>(EntityKey.java:48)
   at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:161)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
   at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38)
   at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:618)
   at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:592)
   at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:596)
   at test.Tester.testZones(Tester.java:54)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at junit.framework.TestCase.runTest(TestCase.java:154)
   at junit.framework.TestCase.runBare(TestCase.java:127)
   at junit.framework.TestResult$1.protect(TestResult.java:106)
   at junit.framework.TestResult.runProtected(TestResult.java:124)
   at junit.framework.TestResult.run(TestResult.java:109)
   at junit.framework.TestCase.run(TestCase.java:118)
   at junit.framework.TestSuite.runTest(TestSuite.java:208)
   at junit.framework.TestSuite.run(TestSuite.java:203)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.String field test.ZoneToZoneSet$Id.zoneSetId to java.lang.String
   at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
   at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
   at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
   at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:18)
   at java.lang.reflect.Field.get(Field.java:358)
   at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:32)
   ... 34 more


This was due to the signature of my id accessors : getId() and setId().
These accessors were setting and returning String objects while they should have been working with ZoneToZoneSet$Id objects. Still, id accessors are needed unlike what I had been led to beleive.

The proper id accessors are :
Code:
   public Id getId (){
      return id;
   }
   
   public void setId (Id id){
      this.id = id;
   }   


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:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.