-->
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: Composite Design Pattern with JPA Annotations
PostPosted: Fri Apr 21, 2006 9:48 am 
Newbie

Joined: Wed Feb 15, 2006 10:17 am
Posts: 13
Location: Rome, Italy
Hi,
I have to model a composite pattern and I would like to benefig of the JPA Annotations and Hibernate

The classes are shown below, let's say in the meanwhile they are the canonical Composite Design Pattern entities, where:
* Component is the (pretending to be) abstract top class
* Leaf is a concrete class which extends Component and has no children
* Composite is a concrete class which extends Component and has a Set<Componet> children

My needs would be that the root class should be abstract, and I want to be able to impose unique contrainsts on the 2 subclasses so that no "equal" entity can be under the same node in the hierarchy (ie: no two Leaves with same content under the same parent node). I would like also to use the JOINED strategy

Hibernate version:
Latest from Maven2 ibiblio repo:
* hibernate-core: 3.1.2
* hibernate-annotations: 3.1beta8

Classes:
These are the 3 classes, with some comments useful to understand why I made some design choices.

/**
* XXX: This class can't be abstract because otherwise I get:
* org.hibernate.InstantiationException: Cannot instantiate abstract class
* or interface my.package.Component
* There is no hibernate sql weird log anway
*/
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Component {

protected Long id;
protected Composite parent;

public Component() {
super();
this.parent = null;
}

@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

/**
* The 1:N association is bidirectional, and the <code>ManyToOne</code> side thus
* must declare <code>mappedBy="parent"</code>,
* and so the <code>parent</code> is actually needed on the super class because otherwise it will say
* <em>""Colum Component.parent not found"</em> or something like that
*
* @return
*/
@ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.MERGE, CascadeType.PERSIST}, optional=true)
public Composite getParent(){
return this.parent;
}

public void setParent(Composite parent){
this.parent = parent;
}
}

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"parent_id", "name"})})
public class Composite extends Component {

private String name;
private Set<Component> children;

public Composite(){
super();
this.children = new HashSet<Component>();
}

@Column(nullable=false)
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

/**
* The <code>parent</code> must be overrided in order to be able to declare
* <code>uniqueConstraints</code> on the class (see this class definition), otherwise
* it will say "Unable to find column with logical name <code>Composite.parent_id</code>"
*/
@Override
@ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.MERGE, CascadeType.PERSIST}, optional=true)
public Composite getParent(){
return this.parent;
}

public void setParent(Composite parent){
this.parent = parent;
}

@OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public Set<Component> getChildren() {
return children;
}

public void setChildren(Set<Component> children) {
this.children = children;
}

/* ==================== */
@Override
public boolean equals(Object obj) {

if(obj == this){
return true;
}
else if(!(obj instanceof Composite)) {
return false;
}else{
Composite composite = (Composite) obj;
return new EqualsBuilder()
.append(this.parent, composite.getParent())
.append(this.name, composite.getName())
.isEquals();
}
}

@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(this.parent)
.append(this.name)
.toHashCode();
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", this.id)
.append("parent", this.parent.getName())
.append("name", this.name)
.toString();
}
}

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"parent_id", "content"})})
public class Leaf extends Component {

private String content;

public Leaf() {
super();
}

@Column(nullable=false)
public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

/**
* The <code>parent</code> must be overrided in order to be able to declare
* <code>uniqueConstraints</code> on the class (see this class definition), otherwise
* it will say "Unable to find column with logical name <code>Leaf.parent_id</code>"
*/
@Override
@ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.MERGE, CascadeType.PERSIST}, optional=true)
public Composite getParent(){
return this.parent;
}

public void setParent(Composite parent){
this.parent = parent;
}

/* ==================== */
@Override
public boolean equals(Object obj) {

if(obj == this){
return true;
}
else if(!(obj instanceof Composite)) {
return false;
}else{
Composite composite = (Composite) obj;
return new EqualsBuilder()
.append(this.parent, composite.getParent())
.append(this.content, composite.getName())
.isEquals();
}
}

@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(this.parent)
.append(this.content)
.toHashCode();
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", this.id)
.append("parent", this.parent.getName())
.append("name", this.content)
.toString();
}
}

Unit test code (DAOs are created with Spring HibernateTemplate that is used throughout the project for other DAOs)

public void testIt() throws Exception {
// DAOs with Spring HibernateTemplate
this.compositeDao.removeAll(); // ok
this.leafDao.removeAll(); // ok

this.root = new Composite();
this.root.setName("root name");
this.root.setParent(null);
this.compositeDao.saveOrUpdate(this.root);
assertEquals(1, this.compositeDao.findAll().size());

this.leafA = new Leaf();
this.leafA.setContent("leaf A content");
this.leafA.setParent(this.root);
this.leafDao.saveOrUpdate(this.leafA);
assertEquals(1, this.leafDao.findAll().size());

Leaf leafB = new Leaf();
leafB.setContent(this.leafA.getContent());
leafB.setParent(this.leafA.getParent());
try{
this.leafDao.saveOrUpdate(leafB);
fail("Must violate unique constraints");
}catch(Exception e){
assertTrue("Ok, unique constraints annotation works", true);
}

/* if the Component top class is abstract here i get exception:
* org.hibernate.InstantiationException: Cannot instantiate abstract class
* or interface my.package.Component
* (There is no hibernate sql log anway)
*
* if Component is not declared abstract (is a concrete class),
* it all works!!
*/
this.leafDao.removeAll(); // throws Exception (see the comment)

this.compositeDao.removeAll(); // does not even reach this point
}

Code between sessionFactory.openSession() and session.close():
Managed by Spring 1.2.6 HibernateTemplate, no problem in this

Full stack trace of any exception that occurs:
(see comments in the code because they are thrown depending on which choices I make in the code: abstract/non abstact Component class, @Override of getParent(), ...)

Name and version of the database you are using:
HsqlDB 1.8.0.1 running in RAM

As you can read in the comments, and in the unit test, the problem is with the Component class that I am "forced" to declare as a concrete class, otherwise I get "org.hibernate.InstantiationException: Cannot instantiate abstract class or interface my.package.Component"

Any help is appreciated, if somebody needs more info just let me know.

Thanks a lot,
Alessio Pace.


Top
 Profile  
 
 Post subject: same problem
PostPosted: Wed Feb 14, 2007 12:26 am 
Newbie

Joined: Wed Aug 03, 2005 2:13 am
Posts: 16
Did anybody every solve this, or has come across it? This post was a long time ago, but I'm now having exactly the same problem.


Top
 Profile  
 
 Post subject: bad data
PostPosted: Wed Feb 14, 2007 12:43 am 
Newbie

Joined: Wed Aug 03, 2005 2:13 am
Posts: 16
as some other forum posts had also indicated, this was due to bad data in my test database.

a better error message would have saved me and all those others SO much time!!

but i'm glad to have found it. basically I had one of my subclasses in the DB pointing to a record in the "super" table that also belonged to another subclass.


Top
 Profile  
 
 Post subject: Re: bad data
PostPosted: Tue Jan 15, 2008 7:37 am 
Newbie

Joined: Tue Jan 15, 2008 7:26 am
Posts: 1
Location: NSW, Australia
jazir1979 wrote:
basically I had one of my subclasses in the DB pointing to a record in the "super" table that also belonged to another subclass.


Ai! Me too. Except that in my case it was a record in the superclass table which was not joined in any subclass table.

The context in which I received the error was entity.getThings().iterator().next(). I would have expected an error when the mappings were read, if Hibernate really thought that it would have to attempt to instantiate an abstract class as a consequence of the mapping.

The mapping was of the:

<class name="MyInterface" table="common">
// properties
<joined-subclass name="MyImpl1" table="type1" />
<joined-subclass name="MyImpl2" table="type2" />
</class>

Even so, a message like 'Could not determine the concrete type of Thing for id = 342' would have been more useful.

For what it's worth, next time I do an object model, I'll try and leave specialization hierarchies right out of it if I can find a satisfactory alternative.


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.