-->
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: Component mapping with annotations
PostPosted: Tue Jul 18, 2006 9:54 am 
Newbie

Joined: Fri Apr 07, 2006 10:52 am
Posts: 17
Hi all,

I have a major problem mapping a base java class as a component. The base class is the java.awt.Point2D class, but this problem applies to any other base class that must be declared as a component.

In my specific problem, I have to map the following hierarchy:

Code:
@Embeddable
public class AntennaChipModule implements Cloneable {

    @Embedded
    @AttributeOverrides( {
        @AttributeOverride(name = "x", column = @Column(name = "chipmodule_x")),
        @AttributeOverride(name = "y", column = @Column(name = "chipmodule_y")),
    } )
    private AntennaPoint position;

    // Irrelevant class stuff removed
}


The position field is mapped as a component using the @Embedded syntax. The object AntennaPoint is this very simple class that extends Point2D.Double to make it @Embeddable and Cloneable:

Code:
@Embeddable()
public class AntennaPoint extends Point2D.Double implements Cloneable {
    public Object clone() {
        return new AntennaPoint(x,y);
    }
}

In case you never used it, Point2D.Double is a very simple class of java.awt with only two fields: x and y, that does not implement the cloneable interface.

The problem is as follows:

  • With the annotations declared as posted above, hibernate completely ignores the x and y properties.
  • I am converting an existing *.hbm.xml mapping to Hibernate Annotations. The previous mapping worked perfectly using the Hibernate standard XML mapping. The component was mapped with normal <property> entries. My database already contains these properties but Hibernate, using the annotations abovem ignores them, and the component is returned as null.
  • The only way that I found to have Hibernate load the properties is to change the AntennaPoint class by adding 2 fields and the appropriate @Column mappings, as follows:
    Code:
    public class AntennaPoint extends Point2D.Double implements Cloneable {
       
        @Column(nullable = false)
        public double x;
        @Column(nullable = false)
        public double y;

        public Object clone() {
            return new AntennaPoint(x,y);
        }
    }
  • This approach makes the properties get loaded correctly, because it seems that Hibernate cannot "AttributeOverride" a field that has no @Column, but it simply breaks the code, because of course "my" x and y fields hold different values from the Point2D.Double parent class.


Is this behaviour correct? How can any non custom class be mapped using annotations as a component if this behaviour is correct?

If it is mandatory to use a @Column annotation for every annotation that must be mapped, and you cannot use a @Column annotation unless you declare the field, the annotation system has some major glitch.

IMHO the @AttributeOverride annotations should have been enough to instruct Hibernate to map the fields of the parent object. If not, what other method can be used?

How can anybody map a java.awt.Line2D or any similar object as a component if this behaviour is correct? I even find very questionable forcing the object as being @Embeddable is stupid enough, because it forces anyone to extend the base classes to a custom class only to declare them as @Embeddable, but the limitation I am posting about seems way too big to have been overlooked. Of course I must assume I am the one who does not know how to map this, and I assume that no such blackhole can be in the annotations specifications or in the Hibernate implementation.

Thanks in advance for any help.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 11:16 am 
Expert
Expert

Joined: Sat Oct 25, 2003 8:49 am
Posts: 490
Location: Vrhnika, Slovenia
Use UserType.
And @Type annotation:
- http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e2097


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 21, 2006 5:56 am 
Newbie

Joined: Fri Apr 07, 2006 10:52 am
Posts: 17
Actually UserTypes and Types have nothing to do with my problem.

Let's just make the problem very very simple. Suppose I have a class:

Code:
public class MyLine2D extends java.awt.Line2D.Double {
}


This class does nothing except extending java.awt.Line2D.Double. I want to make it persistent and save the x1, y1, x2, y2 properties.

How can this be done using annotations? With XML mapping this is as dumb as it seems, but with annotations, you can't use the @Column annotation because the fields are inherited by the parent class.

I guess what I would need is some kind of class-level annotation like

Code:
@SuperClassProperty(name = "x1", column = "x1_column", nullable = false, ...)
public class MyLine2D extends java.awt.Line2D.Double {
}



Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 21, 2006 10:36 am 
Beginner
Beginner

Joined: Wed Apr 26, 2006 2:41 pm
Posts: 30
I've never done it but you could try @AttributeOverride

http://java.sun.com/javaee/5/docs/api/javax/persistence/AttributeOverride.html

It's not really an override per-se but maybe it will work.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 24, 2006 5:15 am 
Newbie

Joined: Fri Apr 07, 2006 10:52 am
Posts: 17
Thanks for your reply. I tried that before, but it does not work. Here is the simple code:

Code:
package test.hibernate;

import java.awt.Dimension;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;

@Entity
@AttributeOverrides({
   @AttributeOverride(name = "width", column = @Column(name = "size_w", nullable = false)),
   @AttributeOverride(name = "height", column = @Column(name = "size_h", nullable = false))
})

@SequenceGenerator(name = "gen_pd_id", sequenceName = "gen_pd_id")
public class PersistentDimension extends Dimension {
   @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "gen_pd_id")
   Long id;
}


The main():

Code:
package test.hibernate;

import org.hibernate.Transaction;

public class AnnotationTest {

   public static void main(String[] args) {
      PersistentDimension pd = new PersistentDimension();
      pd.setSize(4000, 12045);
      Transaction tx = HibernateUtil.getSession().beginTransaction();
      HibernateUtil.getSession().save(pd);
      tx.commit();
   }
}



The result is the following:
Code:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select nextval ('gen_pd_id')
Hibernate: insert into PersistentDimension (id) values (?)

As you can see, the width and height fields from the Dimension class are completely ignored.

Can anybody help? This seems way too big to be only my problem.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 24, 2006 5:15 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
frinkia wrote:
Can anybody help? This seems way too big to be only my problem.


It's actually not that common. We usually work around that by putting a@MappedSuperclass annotation on the component superclasses. This is consistent with the @Entity behavior. In your case this is obviously not possible.

The workarounds are:
- use @Type as ales suggested and map this user type to antenna
- use an orm.xml file to map Point2D.Double as a mapped-superclass

1. definitively works, and 2. should work

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 26, 2006 3:36 am 
Newbie

Joined: Fri Apr 07, 2006 10:52 am
Posts: 17
I will try your suggestions this morning, but you do realize that what you are saying implies directly that there is a hole in the annotation specification. There are some things that you can do with xml mappings that you can't do with annotation mappings. This is a major issue IMHO.

The following class:
Code:
@Entity
public class myClass {
    private Dimension size;
    // Other fields and methods
}

Cannot be mapped unless I use an XML file for the Dimension class. This is hard to believe.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 26, 2006 1:42 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
frinkia wrote:
There are some things that you can do with xml mappings that you can't do with annotation mappings. This is a major issue IMHO.


This is a small price to pay for keeping annotations relatively intuitive

_________________
Emmanuel


Top
 Profile  
 
 Post subject: orm.xml and hibernate specific annotation
PostPosted: Thu May 01, 2008 6:50 am 
Newbie

Joined: Mon Nov 26, 2007 12:49 pm
Posts: 7
Hi guys,

I'm experiencing the same kind of problem as you had in the past.
I know this post is pretty old, but anyway the problem still sometime happens.

So, for me I have more or less the same issue but with different classes and the thing is I can't use @MappedSuperClass on the base classes because they are coming from an external library.
Anyway after fighting a bit I successfully make it (half) worked by using the orm.xml file and declaring the base classes with the <mapped-superclass /> element.

Now I'm still having an issue.
The problem is that one of the class I have has a enum property and I want to use the EnumUserType provided by Gavin King on the hibernate wiki (http://www.hibernate.org/272.html) to prevent me mapping the enum in the database (we all know how mysql sucks with enum types).

So I wanted to use the specific hibernate annotation @Type on the override method but then this is not working at all, it's like hibernate does not see the annotation since the base class is not annotated.


Here is the example to reproduce the problem:

<<Requirement enum>>
Code:
package com.ppp.common.types;

public enum Requirement {
   OPTIONAL,
   REQUIRED,
   MANDATORY;
}



<<BaseClass class>>
This is the base class I can't modify.

Code:
package com.ppp.common.types;

class BaseClass {
   private String property;
   private Requirement requirement;

   public String getProperty() {
      return property;
   }
   
   public void setProperty(String property) {
      this.property = property;
   }

   public Requirement getRequirement() {
      return requirement;
   }
   
   public void setRequirement(Requirement requirement) {
      this.position = requirement;
   }
}



<<orm.xml>>
Here is the orm.xml mapping I'm using to declare the mapped-superclass.

Code:
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
   version="1.0">
   <mapped-superclass class="com.ppp.common.types.BaseClass">
      <attributes>
         <basic name="property" />
         <basic name="requirement">
            <column name="requirement" column-definition="tinyint" nullable="false" />
         </basic>
      </attributes>
   </mapped-superclass>
</entity-mappings>



<<BaseEntity class>>
Here is the implementation I'm using to map the base class into the DB.

Code:
@Entity
class BaseEntity extends BaseClass implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;

   public Long getId() {
      return id;
   }
   
   public void setId(Long id) {
      this.id = id;
   }
   
   @Override
   @Type(
         type = "com.myorg.common.hibernate.EnumUserType",  // com.myorg.common.hibernate.EnumUserType is based on the EnumUserType provided by Gavin King.
         parameters = {
            @Parameter(name = "enumClassName", value = "com.ppp.common.types.Requirement")
         }
   )
   public Requirement getRequirement() {
      return super.getRequirement();
   }
}



So the more I think about this, the more I think it's a kind of a bug... is it? I'm not really sure because the hibernate documentation clearly says:
Quote:
2.2.4.4. Inherit properties from superclasses
This is sometimes useful to share common properties through a technical or a business superclass without including it as a regular mapped entity (ie no specific table for this entity). For that purpose you can map them as @MappedSuperclass.

[ ... ]

Note

Properties from superclasses not mapped as @MappedSuperclass are ignored.

Note

Any class in the hierarchy non annotated with @MappedSuperclass nor @Entity will be ignored.


But still, the class itself is not annotated, but the orm.xml mapping file declares the <mapped-superclass /> which should be the equivalent...

Any comments or suggestions getting the @Type working are greatly appreciated.


Cheers,
/Benoit


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.