in Eclipse, EJB, EJB 3.0, Hibernate, JPA

Eclipse Dali vs Hibernate Tools

The process of mapping tables to entities is greatly simplified with tools like Eclipse Dali and Hibernate Tools, both available as Eclipse plugins. It avoids mapping them by hand, which in my opinion is prone to mapping errors and takes more time. And I really do not see why one should map them by hand when great tools like Eclipse Dali and Hibernate Tools are available.
In my book, I describe the use of the Eclipse Dali plugin to automatically generate the entities.
Lately I have also used Hibernate Tools and I have already noticed a few differences between these two tools.
I am going to list some of these differences.

1) If your database contains a table with no primary key (for whatever reason), Dali will not generate a composite primary key class whereas Hibernate Tools will.
For example, if the table CONTACT contains the fields contactId, email, nom, prenom, telephone, titre and none of them is declared as a primary key then :
– Dali will generate an entity class Contact.java with an error message complaining that “The entity has no primary key attribute defined”.
– Hibernate Tools will generate an entity class Contact.java and also a ContactId.java class, annotated with @Embeddable.

Contact.java :

package com.hibtools.jpa;

// Generated 8 mai 2011 18:22:07 by Hibernate Tools 3.4.0.CR1

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * Contact generated by hbm2java
 */
@Entity
@Table(name = "CONTACT")
public class Contact implements java.io.Serializable {

	private ContactId id;

	public Contact() {
	}

	public Contact(ContactId id) {
		this.id = id;
	}

	@EmbeddedId
	@AttributeOverrides({
			@AttributeOverride(name = "contactid", column = @Column(name = "CONTACTID", nullable = false, scale = 0)),
			@AttributeOverride(name = "email", column = @Column(name = "EMAIL")),
			@AttributeOverride(name = "nom", column = @Column(name = "NOM")),
			@AttributeOverride(name = "prenom", column = @Column(name = "PRENOM")),
			@AttributeOverride(name = "telephone", column = @Column(name = "TELEPHONE", nullable = false, precision = 10, scale = 0)),
			@AttributeOverride(name = "titre", column = @Column(name = "TITRE")) })
	public ContactId getId() {
		return this.id;
	}

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

}

ContactId.java :

package com.hibtools.jpa;

// Generated 8 mai 2011 18:22:07 by Hibernate Tools 3.4.0.CR1

import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * ContactId generated by hbm2java
 */
@Embeddable
public class ContactId implements java.io.Serializable {

	private BigDecimal contactid;
	private String email;
	private String nom;
	private String prenom;
	private long telephone;
	private String titre;

	public ContactId() {
	}

	public ContactId(BigDecimal contactid, long telephone) {
		this.contactid = contactid;
		this.telephone = telephone;
	}

	public ContactId(BigDecimal contactid, String email, String nom,
			String prenom, long telephone, String titre) {
		this.contactid = contactid;
		this.email = email;
		this.nom = nom;
		this.prenom = prenom;
		this.telephone = telephone;
		this.titre = titre;
	}

	@Column(name = "CONTACTID", nullable = false, scale = 0)
	public BigDecimal getContactid() {
		return this.contactid;
	}

	public void setContactid(BigDecimal contactid) {
		this.contactid = contactid;
	}

	@Column(name = "EMAIL")
	public String getEmail() {
		return this.email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Column(name = "NOM")
	public String getNom() {
		return this.nom;
	}

	public void setNom(String nom) {
		this.nom = nom;
	}

	@Column(name = "PRENOM")
	public String getPrenom() {
		return this.prenom;
	}

	public void setPrenom(String prenom) {
		this.prenom = prenom;
	}

	@Column(name = "TELEPHONE", nullable = false, precision = 10, scale = 0)
	public long getTelephone() {
		return this.telephone;
	}

	public void setTelephone(long telephone) {
		this.telephone = telephone;
	}

	@Column(name = "TITRE")
	public String getTitre() {
		return this.titre;
	}

	public void setTitre(String titre) {
		this.titre = titre;
	}

	public boolean equals(Object other) {
		if ((this == other))
			return true;
		if ((other == null))
			return false;
		if (!(other instanceof ContactId))
			return false;
		ContactId castOther = (ContactId) other;

		return ((this.getContactid() == castOther.getContactid()) || (this
				.getContactid() != null && castOther.getContactid() != null && this
				.getContactid().equals(castOther.getContactid())))
				&& ((this.getEmail() == castOther.getEmail()) || (this
						.getEmail() != null && castOther.getEmail() != null && this
						.getEmail().equals(castOther.getEmail())))
				&& ((this.getNom() == castOther.getNom()) || (this.getNom() != null
						&& castOther.getNom() != null && this.getNom().equals(
						castOther.getNom())))
				&& ((this.getPrenom() == castOther.getPrenom()) || (this
						.getPrenom() != null && castOther.getPrenom() != null && this
						.getPrenom().equals(castOther.getPrenom())))
				&& (this.getTelephone() == castOther.getTelephone())
				&& ((this.getTitre() == castOther.getTitre()) || (this
						.getTitre() != null && castOther.getTitre() != null && this
						.getTitre().equals(castOther.getTitre())));
	}

	public int hashCode() {
		int result = 17;

		result = 37 * result
				+ (getContactid() == null ? 0 : this.getContactid().hashCode());
		result = 37 * result
				+ (getEmail() == null ? 0 : this.getEmail().hashCode());
		result = 37 * result
				+ (getNom() == null ? 0 : this.getNom().hashCode());
		result = 37 * result
				+ (getPrenom() == null ? 0 : this.getPrenom().hashCode());
		result = 37 * result + (int) this.getTelephone();
		result = 37 * result
				+ (getTitre() == null ? 0 : this.getTitre().hashCode());
		return result;
	}

}

2) Hibernate Tools is capable of generating DAO classes whereas Dali cannot.
For instance, using EJB3 annotations, the generated DAO for the Contact entity is :

package com.hibtools.jpa;

// Generated 8 mai 2011 18:22:07 by Hibernate Tools 3.4.0.CR1

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Home object for domain model class Contact.
 * @see com.hibtools.jpa.Contact
 * @author Hibernate Tools
 */
@Stateless
public class ContactHome {

	private static final Log log = LogFactory.getLog(ContactHome.class);

	@PersistenceContext
	private EntityManager entityManager;

	public void persist(Contact transientInstance) {
		log.debug("persisting Contact instance");
		try {
			entityManager.persist(transientInstance);
			log.debug("persist successful");
		} catch (RuntimeException re) {
			log.error("persist failed", re);
			throw re;
		}
	}

	public void remove(Contact persistentInstance) {
		log.debug("removing Contact instance");
		try {
			entityManager.remove(persistentInstance);
			log.debug("remove successful");
		} catch (RuntimeException re) {
			log.error("remove failed", re);
			throw re;
		}
	}

	public Contact merge(Contact detachedInstance) {
		log.debug("merging Contact instance");
		try {
			Contact result = entityManager.merge(detachedInstance);
			log.debug("merge successful");
			return result;
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw re;
		}
	}

	public Contact findById(ContactId id) {
		log.debug("getting Contact instance with id: " + id);
		try {
			Contact instance = entityManager.find(Contact.class, id);
			log.debug("get successful");
			return instance;
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}
}

3) Not a difference but worth to mention : both tools can detect many-to-many tables associations. Meaning that the tools are intelligent enough to know that a table is a join table and should not be mapped into an entity.

4) With Dali, you can edit table associations before generating the entities.
For instance in the following screenshot, I edit the association between the COMMANDE and ADRESSE entities. By default, all associations are bidirectionnal.
If i want the association to be unidirectional, so that there is no reference to a collection of COMMANDE in ADRESSE, then i can uncheck the checkbox during the wizard.

Dali1

I have not checked the reveng.xml file in Hibernate Tools. It allows you to control “certain aspects of the reverse engineering” and I suppose one could control these association types, using this file but not the wizard.
http://docs.jboss.org/tools/2.0.0.GA/hibernatetools/en/html_single/index.html#reverseengineering

5) Something i also like about Dali is the ability to specify which type of collection properties we want to use : java.util.Set or java.util.List. By default, Hibernate Tools generates java.util.Set type of collections.

My conclusion is that for a one-time entities generating process, Dali is capable of doing a perfect job. But if the model often changes, meaning that the entities need to be modified continuously because the tables have changed (new columns, new foreign keys, new associations etc) then Hibernate Tools is the best option because you only need to keep the reveng.xml file up to date with the new database changes.