-->
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.  [ 6 posts ] 
Author Message
 Post subject: Trouble with component in subclass (collection of values)
PostPosted: Sat Jul 23, 2005 1:22 pm 
I'm having trouble with a collection of value-objects (composite element) within a subclass (table per class strategy). I get a PropertyAccessException when trying to create/insert the object. If I use the <set> in the mapping document (in comments im xml) instead of <bag> or <idbag> it works. But then again I can't have not-null properties (wich i need).

Any help, comments, input, suggestions how to handle this?

thanks,
-andi


Hibernate version: 3.0.x

Mapping documents:
Code:
   <class name="Party" table="PARTIES">

      <id name="UID" type="long" column="UID"><generator class="native" /></id>
      <version name="version" column="VERSION" type="integer"/>

      <!--
      Bidirectional, required as Party is MANAGERID NOT NULL. This is also
      a read-only property that will never be updated. -->
      <many-to-one name="user" class="User" column="USERUID" update="false" outer-join="false" foreign-key="FK1_USERUID"/>

      <joined-subclass name="Person" table="PERSONS">

         <key column="UID" foreign-key="FK1_PERSONUID"/>

         <!-- TODO-LOW: write NameUserType -->
         <component name="name" class="Name">
            <property name="title" type="string"/>
            <property name="first" type="string" not-null="true"/>
            <property name="middle" type="string"/>
            <property name="last" type="string" not-null="true"/>
            <property name="suffix" type="string"/>
         </component>

<bag name="phones" table="PERSONPHONES">
    <key column="PERSONUID"/>
   <composite-element class="Phone">
      <property name="type" type="PhoneType" not-null="true"/>
      <property name="countrycode" type="string" length="3" not-null="true"/>
        <property name="areacode" type="string"/>
        <property name="number" type="string"/>
      <property name="extension" type="string"/>
    </composite-element>
</bag>

         <!--
         <set name="phones" table="PERSONPHONES" lazy="true">
            <key column="PERSONUID"/>
            <composite-element class="Phone">
               <property name="type" type="PhoneType"/>
               <property name="countrycode" type="string" length="3"/>
                    <property name="areacode" type="string"/>
                    <property name="number" type="string"/>
               <property name="extension" type="string"/>
                </composite-element>
         </set>
         -->
      </joined-subclass>



Full stack trace of any exception that occurs:
Code:
Exception in thread "main" org.hibernate.PropertyAccessException: could not set a field value by reflection setter of perfectmind.domain.Person.phones
   at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:81)
   at org.hibernate.tuple.AbstractTuplizer.setPropertyValues(AbstractTuplizer.java:207)
   at org.hibernate.tuple.PojoTuplizer.setPropertyValues(PojoTuplizer.java:176)
   at org.hibernate.persister.entity.BasicEntityPersister.setPropertyValues(BasicEntityPersister.java:2919)
   at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:225)
   at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:160)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:95)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
   at org.hibernate.engine.Cascades$5.cascade(Cascades.java:154)
   at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
   at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:895)
   at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:792)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
   at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:363)
   at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
   at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:160)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:95)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
   at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
   at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.save(SessionImpl.java:481)
   at org.hibernate.impl.SessionImpl.save(SessionImpl.java:476)
   at $Session_10544ad1c24.save($Session_10544ad1c24.java)
   at $Session_10544ad1c25.save($Session_10544ad1c25.java)
   at perfectmind.persistence.repositories.HibernateUserRepository.addUser(HibernateUserRepository.java:69)
   at $UserRepository_10544ad1c18.addUser($UserRepository_10544ad1c18.java)
   at perfectmind.service.impl.UserMaintServiceImpl.addUser(UserMaintServiceImpl.java:32)
   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:585)
   at org.apache.hivemind.lib.impl.MethodInterceptorFactory$MethodInvocationImpl.proceed(MethodInterceptorFactory.java:127)
   at perfectmind.persistence.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:65)
   at perfectmind.persistence.TransactionInterceptor.invoke(TransactionInterceptor.java:46)
   at $MethodInterceptor_10544ad1c1e.invoke($MethodInterceptor_10544ad1c1e.java)
   at org.apache.hivemind.lib.impl.MethodInterceptorFactory$MethodInterceptorInvocationHandler.invoke(MethodInterceptorFactory.java:87)
   at $Proxy0.addUser(Unknown Source)
   at $UserMaintService_10544ad1c14.addUser($UserMaintService_10544ad1c14.java)
   at perfectmind.maint.SetupDatabase.main(SetupDatabase.java:115)
Caused by: java.lang.IllegalArgumentException
   at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
   at java.lang.reflect.Field.set(Field.java:656)
   at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:78)
   ... 46 more


Top
  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 1:44 am 
Regular
Regular

Joined: Tue Nov 09, 2004 5:15 pm
Posts: 100
Please refer to http://forum.hibernate.org/viewtopic.ph ... sexception


Per that thread, you need to write your own UserType.

Hope this helps!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 6:21 am 
Hi saa1,

Thanks for your answer. I read that post before but it's not the same problem than I have. Mine is not realted with CGLIB in any way.

A UserType for the idbag or for the composite-element? That would be a bit strange since using an idbag with a composite-element is encouraged all over ther forum. The tables are created as well.

Code:
<bag name="phones" table="PERSONPHONES">
    <key column="PERSONUID"/>
   <composite-element class="Phone">
      <property name="type" type="PhoneType" not-null="true"/>
      <property name="countrycode" type="string" length="3" not-null="true"/>
        <property name="areacode" type="string"/>
        <property name="number" type="string"/>
      <property name="extension" type="string"/>
    </composite-element>
</bag>


Replacing <bag> with <set> here works fine so it can't be a component-type-thing, can it?

best
andi


Top
  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 7:47 am 
Ok, I got a bit closer now. If I put the whole thing into the _superclass_ mapping it works as excpected (see below). So why isn't it possible to have a collection of values mapped as <idbag> (or <bag>) in a joined-subclass?

Am I missing something obvious? Any hints and help on this greatly appreciated. If this does not work it would be a huge limitation. I don't want to model my values (in this case Phone numbers) as entities since they're values.

-andi

WORKING:
Code:
<hibernate-mapping package="perfectmind.domain" default-access="field">
   <class name="Party" table="PARTIES">
      <id name="UID" type="long" column="UID"><generator class="native" /></id>
      <version name="version" column="VERSION" type="integer"/>
      <many-to-one name="user" class="User" column="USERUID" update="false" outer-join="false" foreign-key="FK1_USERUID"/>

      <idbag name="phones" table="PARTYPHONES">
         <collection-id column="UID" type="long"><generator class="hilo" /></collection-id>
          <key column="PARTYUID"/>
         <composite-element class="Phone">
            <property name="type" type="PhoneType" not-null="true"/>
            <property name="countrycode" type="string" length="3" not-null="true"/>
              <property name="areacode" type="string" not-null="true"/>
              <property name="number" type="string" not-null="true"/>
            <property name="extension" type="string" not-null="true"/>
          </composite-element>
      </idbag>

      <joined-subclass name="Person" table="PERSONS">
         <key column="UID" foreign-key="FK1_PERSONUID"/>

         <component name="name" class="Name">
            <property name="title" type="string"/>
            <property name="first" type="string" not-null="true"/>
            <property name="middle" type="string"/>
            <property name="last" type="string" not-null="true"/>
            <property name="suffix" type="string"/>
         </component>
      </joined-subclass>
</class>
</hibernate-mapping>


NOT WORKING:
Code:
<hibernate-mapping package="perfectmind.domain" default-access="field">
   <class name="Party" table="PARTIES">
      <id name="UID" type="long" column="UID"><generator class="native" /></id>
      <version name="version" column="VERSION" type="integer"/>
      <many-to-one name="user" class="User" column="USERUID" update="false" outer-join="false" foreign-key="FK1_USERUID"/>

      <joined-subclass name="Person" table="PERSONS">
         <key column="UID" foreign-key="FK1_PERSONUID"/>

         <component name="name" class="Name">
            <property name="title" type="string"/>
            <property name="first" type="string" not-null="true"/>
            <property name="middle" type="string"/>
            <property name="last" type="string" not-null="true"/>
            <property name="suffix" type="string"/>
         </component>

      <idbag name="phones" table="PARTYPHONES">
         <collection-id column="UID" type="long"><generator class="hilo" /></collection-id>
          <key column="PARTYUID"/>
         <composite-element class="Phone">
            <property name="type" type="PhoneType" not-null="true"/>
            <property name="countrycode" type="string" length="3" not-null="true"/>
              <property name="areacode" type="string" not-null="true"/>
              <property name="number" type="string" not-null="true"/>
            <property name="extension" type="string" not-null="true"/>
          </composite-element>
      </idbag>

      </joined-subclass>
</class>
</hibernate-mapping>


Top
  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 9:49 am 
I've solved the problem - though, I'm not quite happy with it. Indeed there seems to be a requirement for a custom composite user type to have a non-<set> collection of values within a joined-subclass. So the only way is writing a usertype for all values. I see this is better style to do with all user types anyways. But for quick and dirty testing i prefer to do the mapping with <composite-element>.

Any plans to support this without the need of a custom user type???

Anyways, here's the complete code for a Phone(Number) value and the related usertype as well as mapping examples. Hope someone can use it.

best,
andi


Phone (number) value
Code:
import java.io.Serializable;

/**
* Value that identifies and typifies a phone number.
* <p>
* A phone number can be a phone, fax, cellphone, or data line and consists of
* the following parts:
* <p>
* <strong>Type of phone</strong><br />
* Type of data per {@link PhoneType}.
* <p>
* <strong>Country Code</strong><br />
* One to three digit international calling code country designation as
* specified by ITU (International Telecommunication Union) E.164.
* See http://www.itu.int/itudoc/itu-t/ob-lists/icc/e164_763.html.
* <p>
* <strong>Area Code</strong><br />
* For US numbers, this is the 3-digit NANP (North American Numbering Plan)
* initial portion of a domestic telephone number, corresponding to a region,
* city or part of a city. For a foreign address this can be a city code.
* <p>
* <strong>Number</strong><br />
* The remainder of a foreign or domestic number. It will be 7 digits for US
* numbers, variable for foreign.
* <p>
* <strong>Extension</strong><br />
* An optional, numeric extension number. In calling, this is technically not
* a part of the number itself, but an access code used to further route a
* call once a connection has been made. This field can also be used to store
* Dataline specific comments (i.e. 069-121212 Leonardo).
* <p>
* Example: 049 06532 12458 10
* <p>
* Please note that no replacements are done with the stored version. So if you
* need a special formatting use the displayName() methods in this class.
*
* @author  Andreas Aderhold, All rights reserved
* @version $Id$
*/
public final class Phone implements Serializable/*, Comparable*/ {

   // ~ Fields ----------------------------------------------------------------

   private PhoneType type;

   /*One to three digit international calling code country designation as specified by ITU (International Telecommunication Union) E.164. See http://www.itu.int/itudoc/itu-t/ob-lists/icc/e164_763.html.*/
   private String countrycode;

   private String areacode;
   private String number;
   private String extension;

   // ~ Constructors ----------------------------------------------------------

   /** Default constructor, do not use */
   private Phone() {}

   private Phone(PhoneType type, String countrycode, String areacode, String number, String extension) {
      this.type = type;
      this.countrycode = countrycode;
      this.areacode = areacode;
      this.number = number;
      this.extension = extension;
   }

   // ~ Factories -------------------------------------------------------------

   public static Phone newPhone(PhoneType type, String countrycode, String areacode, String number, String extension) {
      return new Phone(type, countrycode, areacode, number, extension);
   }

   public static Phone newPhone(String countrycode, String areacode, String number, String extension) {
      return new Phone(PhoneType.Phone, countrycode, areacode, number, extension);
   }

   public static Phone newFax(String countrycode, String areacode, String number, String extension) {
      return new Phone(PhoneType.Fax, countrycode, areacode, number, extension);
   }

   public static Phone newCellphone(String countrycode, String areacode, String number, String extension) {
      return new Phone(PhoneType.Cellphone, countrycode, areacode, number, extension);
   }

   // ~ Business methods ------------------------------------------------------

   public PhoneType type() {
      return this.type;
   }

   public String countrycode() {
      return this.countrycode;
   }

   public String areacode() {
      return this.areacode;
   }

   public String number() {
      return this.number;
   }

   public String extension() {
      return this.extension;
   }

   public boolean isFax() {
      return type.compareTo(PhoneType.Fax) == 0;
   }

   public boolean isCellphone() {
      return type.compareTo(PhoneType.Cellphone) == 0;
   }

   public boolean isPhone() {
      return type.compareTo(PhoneType.Phone) == 0;
   }

   public boolean isData() {
      return type.compareTo(PhoneType.Data) == 0;
   }

   public String displayName() {
      return type.getPhoneType() + ":" + countrycode + '-' + areacode + '-' + number + ' ' + extension;
   }

   // ~ System methods --------------------------------------------------------

   public String toString() {
      return displayName();
   }

   public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof Phone)) return false;
      final Phone p = (Phone) o;
      if (type.compareTo(p.type) != 0) return false;
      if (!countrycode.equals(p.countrycode)) return false;
      if (!areacode.equals(p.areacode)) return false;
      if (!number.equals(p.number)) return false;
      return extension.equals(p.extension);
   }

   public int hashCode() {
      int result;
      result = type.hashCode();
      result = 29 * result + ((areacode != null) ? areacode.hashCode() : 0);
      result = 29 * result + ((countrycode != null) ? countrycode.hashCode() : 0);
      result = 29 * result + ((number != null) ? number.hashCode() : 0);
      result = 29 * result + ((extension != null) ? extension.hashCode() : 0);
      return result;
   }


   // ~ Private Methods -------------------------------------------------------

}



The type enum
Code:
public enum PhoneType {
   Phone("Phone"),
   Fax("Fax"),
   Cellphone("Cellphone"),
   Data("Data"),
   HomePhone("HomePhone"),
   HomeFax("HomeFax");

   private final String phonetype;

   private PhoneType(String phonetype) {
      this.phonetype = phonetype;
   }

   final String getPhoneType() { return this.phonetype; }
}






Code:
public final class PhoneCompositeUserType implements CompositeUserType {

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

   public boolean equals(Object x, Object y) {
      if (x == y) return true;
      if (x == null || y == null) return false;
      return x.equals(y);
   }

   public int hashCode(Object o) throws HibernateException {
      return o.hashCode();
   }

   public Serializable disassemble(Object value, SessionImplementor si) throws HibernateException {
      return (Serializable) value;
   }

   public Object assemble(Serializable cached, SessionImplementor si, Object owner) throws HibernateException {
      return cached;
   }

   // TODO: Whats this?
   public Object replace(Object original, Object target, SessionImplementor si, Object owner) throws HibernateException {
      return null;
   }

   public Object deepCopy(Object value) {
      return value; // Phone vlaue is immutable
   }

   public boolean isMutable() {
      return false;
   }

   public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {

      if (resultSet.wasNull()) {
         return null;
      }

      String typeName = resultSet.getString(names[0]);
      PhoneType type = resultSet.wasNull() ? null : Enum.valueOf(PhoneType.class, typeName);

      String countrycode = resultSet.getString(names[1]);
      String areacode = resultSet.getString(names[2]);
      String number = resultSet.getString(names[3]);
      String extension = resultSet.getString(names[4]);

      return Phone.newPhone(type, countrycode, areacode, number, extension);
   }

   public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {

      if (value == null) {
          statement.setNull(index, Types.VARCHAR);
          statement.setNull(index + 1, Types.VARCHAR);
         statement.setNull(index + 2, Types.VARCHAR);
         statement.setNull(index + 3, Types.VARCHAR);
         statement.setNull(index + 4, Types.VARCHAR);
      } else {
         Phone phone = (Phone) value;
          statement.setString(index, ((Enum) phone.type()).name());
          statement.setString(index + 1, phone.countrycode());
         statement.setString(index + 2, phone.areacode());
         statement.setString(index + 3, phone.number());
         statement.setString(index + 4, phone.extension());
      }
   }

   public String[] getPropertyNames() {
      return new String[] { "type", "countrycode", "areacode", "number", "extension" };
   }

   public Type[] getPropertyTypes() {
      return new Type[] { Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING };
   }

   public Object getPropertyValue(Object component, int property) throws HibernateException {
        Phone phone = (Phone) component;
        if (property == 0) return phone.type();
        if (property == 1) return phone.countrycode();
        if (property == 2) return phone.areacode();
        if (property == 3) return phone.number();
        if (property == 4) return phone.extension();
      return null;
   }

   public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
       throw new UnsupportedOperationException("Phone is immutable");
   }

}


Mapping example:
Code:
<hibernate-mapping package="domain" default-access="field">

   <typedef name="PhoneUserType" class="perfectmind.persistence.types.PhoneCompositeUserType" />

   <class name="Party" table="PARTIES">
      <id name="UID" type="long" column="UID"><generator class="native" /></id>

              ....

      <joined-subclass name="Person" table="PERSONS">
         <key column="UID" foreign-key="FK1_PERSONUID"/>
                     
                      ....

         <bag name="phones" table="PERSONPHONES">
             <key column="PSERONUID"/>
            <element type="PhoneUserType">
               <column name="TYPE" not-null="true"/>
               <column name="COUNTRYCODE" length="3" not-null="true"/>
               <column name="AREACODE" not-null="true"/>
               <column name="NUMBER" not-null="true"/>
               <column name="EXTENSION" not-null="true"/>
            </element>
         </bag>

      </joined-subclass>
</class>

</hibernate-mapping>


Top
  
 
 Post subject:
PostPosted: Sun Jul 24, 2005 1:24 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Looks like you are making some mistake somewhere. There should be no problem having a bag on a joined-subclass. Certainly you do not need to write any strange usertypes. I think you have misdiagnosed the problem.

Especially, you have not actually explained the cause of the IllegalArgumentException that occurs. How about diagnosing that one in your debugger first, before starting to do all kinds of wierd things.


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