Solutions to IT problems

Solutions I found when learning new IT stuff

Spring 3 and Hibernate 4 for beginners

with 6 comments


Introduction Comments

One would assume there are tons of tutorials and blog post out there about this topic. This is true. There are actually so many it is hard to find one that is up to date and fits your level of knowledge. Most of them assume you are already rather good in using Spring, Hibernate or both. So some very fundamental stuff is never mentioned and that stuff will make your application throw exceptions all over the place. I mainly had trouble with the configuration file and were to put what annotation.

Scope of this Article

This article covers my first steps in using Spring and Hibernate together to create a very basic Data Access Layer. I have never used Spring or Hibernate before in a real application. During my studies in a project I once made a simple app using JPA with TopLink. Some very basic knowledge is required like you should probably have seen an @Entity annotation before (else google it) but in general this is an article from a beginner for beginners. You will need to now basic relational database terms and design principles. The project uses maven and hence you should now some basics of it. Also some knowledge in chemistry will make it easier to understand the example but that is not required. Feel free to comment if you have improvements or suggestions to the design and code shown in this article.

The Problem

The DAL I created should be able to store “chemical compounds”. What is a “chemical compound”? It’s a mixture of substances and each substance occurs in a compound in a percentage. Just like whiskey is a mixture of 40 % ethanol and 60 % water (of course this is a simplified view but you get what I mean). Note that a “substance” has a specific “chemical structure”, eg. its known of which atoms it consists and how they are linked together. To summarize we can say a chemical compound consist multiple “chemical structures” (substances) and a “chemical structure” (substance) can occur in multiple compounds. This is a classic many-to-many relationship.

Hibernate and many-to-many with percentage

It turned out that there is no simple way to create a many-to-many relationship in hibernate where the “link table” has an additional column (the percentage of the substance in the compound). I followed this tutorial and therefore created the java classes as shown in the next section. As a summary you will need to create two one-to-many relationships and a linker class. But in practice it is even more complicated.

The Entity classes

ChemicalStructure

Nothing special here, eg. documentation and comments are sparse ;)..funny comments aside the important part is the @OneToMany annotation towards the bottom of the class and its “mappedBy = “pk.chemicalStructure” attribute.

<br />package org.bitbucket.kienerj.moleculedatabaseframework.entityclasses;<br /><br />import java.io.Serializable;<br />import java.util.Set;<br />import javax.persistence.CascadeType;<br />import javax.persistence.Column;<br />import javax.persistence.Entity;<br />import javax.persistence.FetchType;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.GenerationType;<br />import javax.persistence.Id;<br />import javax.persistence.OneToMany;<br />import javax.persistence.SequenceGenerator;<br />import javax.persistence.Table;<br /><br />@Entity<br />@Table(name = "chemical_structure")<br />public class ChemicalStructure implements Serializable {<br /><br /><%%KEEPWHITESPACE%%>    private Long id;<br /><%%KEEPWHITESPACE%%>    private String structureKey;<br /><%%KEEPWHITESPACE%%>    private String structureData;<br /><%%KEEPWHITESPACE%%>    private Set occurence;<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the id<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Id<br /><%%KEEPWHITESPACE%%>    @GeneratedValue(strategy = GenerationType.AUTO, generator = "chem_structure_seq_gen")<br /><%%KEEPWHITESPACE%%>    @SequenceGenerator(name = "chem_structure_seq_gen", sequenceName = "seq_chemical_structure")<br /><%%KEEPWHITESPACE%%>    @Column(name = "structure_id")<br /><%%KEEPWHITESPACE%%>    public Long getId() {<br /><%%KEEPWHITESPACE%%>        return id;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param id the id to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setId(Long id) {<br /><%%KEEPWHITESPACE%%>        this.id = id;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the structureKey<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Column(name = "structure_key", unique = true)<br /><%%KEEPWHITESPACE%%>    public String getStructureKey() {<br /><%%KEEPWHITESPACE%%>        return structureKey;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param structureKey the structureKey to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setStructureKey(String structureKey) {<br /><%%KEEPWHITESPACE%%>        this.structureKey = structureKey;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the structureData<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Column(name = "chemical_structure")<br /><%%KEEPWHITESPACE%%>    public String getStructureData() {<br /><%%KEEPWHITESPACE%%>        return structureData;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param structureData the structureData to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setStructureData(String structureData) {<br /><%%KEEPWHITESPACE%%>        this.structureData = structureData;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.chemicalStructure",<br /><%%KEEPWHITESPACE%%>            cascade = CascadeType.ALL)<br /><%%KEEPWHITESPACE%%>    public Set getOccurence() {<br /><%%KEEPWHITESPACE%%>        return occurence;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    public void setOccurence(Set occurence) {<br /><%%KEEPWHITESPACE%%>        this.occurence = occurence;<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

ChemicalCompound

Very similar to ChemicalStructure. Also note the @OneToMany annotation. Here there is some additonal stuff going on. This entity class is configured to be sub-classed. All subclasses will be stored in the same table were the column “compound_type” stores to what entity class a certain row belongs to.

<br />package org.bitbucket.kienerj.moleculedatabaseframework.entityclasses;<br /><br />import java.io.Serializable;<br />import java.util.HashSet;<br />import java.util.Set;<br />import javax.persistence.CascadeType;<br />import javax.persistence.Column;<br />import javax.persistence.DiscriminatorColumn;<br />import javax.persistence.DiscriminatorType;<br />import javax.persistence.DiscriminatorValue;<br />import javax.persistence.Entity;<br />import javax.persistence.FetchType;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.GenerationType;<br />import javax.persistence.Id;<br />import javax.persistence.Inheritance;<br />import javax.persistence.InheritanceType;<br />import javax.persistence.OneToMany;<br />import javax.persistence.SequenceGenerator;<br />import javax.persistence.Table;<br />import org.bitbucket.kienerj.moleculedatabaseframework.HashCodeUtil;<br /><br />@Entity<br />@Inheritance(strategy = InheritanceType.SINGLE_TABLE)<br />@Table(name = "chemical_compound")<br />@DiscriminatorColumn(name = "compound_type", discriminatorType=DiscriminatorType.STRING)<br />@DiscriminatorValue("ChemicalCompound")<br />public class ChemicalCompound implements Serializable {<br /><br /><%%KEEPWHITESPACE%%>    private Long id;<br /><%%KEEPWHITESPACE%%>    private String compoundName;<br /><%%KEEPWHITESPACE%%>    private Set composition = new HashSet();<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the id<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Id<br /><%%KEEPWHITESPACE%%>    @GeneratedValue(strategy = GenerationType.AUTO, generator = "chem_compound_seq_gen")<br /><%%KEEPWHITESPACE%%>    @SequenceGenerator(name = "chem_compound_seq_gen", sequenceName = "seq_chem_compound")<br /><%%KEEPWHITESPACE%%>    @Column(name = "chem_compound_id")<br /><%%KEEPWHITESPACE%%>    public Long getId() {<br /><%%KEEPWHITESPACE%%>        return id;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param id the id to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setId(Long id) {<br /><%%KEEPWHITESPACE%%>        this.id = id;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the compoundName<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Column(name = "compound_name")<br /><%%KEEPWHITESPACE%%>    public String getCompoundName() {<br /><%%KEEPWHITESPACE%%>        return compoundName;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param compoundName the compoundName to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setCompoundName(String compoundName) {<br /><%%KEEPWHITESPACE%%>        this.compoundName = compoundName;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.compound", cascade = CascadeType.ALL)<br /><%%KEEPWHITESPACE%%>    public Set getComposition() {<br /><%%KEEPWHITESPACE%%>        return composition;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    public void setComposition(Set composition) {<br /><%%KEEPWHITESPACE%%>        this.composition = composition;<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

Now the special or should I say non-intuitive part for which you need to either read the whole hibernate manual or find a tutorial to be able to figure it out. Maybe there is a simpler way but I was lazy and went with the tutorial.

You need the “linker class” defining the “linker table”. That class contains an “ID Class”, ChemicalCompoundCompositionID, which is annotated with @Embeddable. This “ID Class” is used as the primary key (pk) in the “linker class”. But I suggest you look at the code. It’s rather easy to understand but to figure it out yourself…not so much.

ChemicalCompoundComposition

<br />package org.bitbucket.kienerj.moleculedatabaseframework.entityclasses;<br /><br />import java.io.Serializable;<br />import javax.persistence.AssociationOverride;<br />import javax.persistence.AssociationOverrides;<br />import javax.persistence.Column;<br />import javax.persistence.EmbeddedId;<br />import javax.persistence.Entity;<br />import javax.persistence.JoinColumn;<br />import javax.persistence.Table;<br />import javax.persistence.Transient;<br /><br />@Entity<br />@Table(name = "compound_composition")<br />@AssociationOverrides({<br /><%%KEEPWHITESPACE%%>    @AssociationOverride(name = "pk.chemicalStructure",<br /><%%KEEPWHITESPACE%%>    joinColumns =<br /><%%KEEPWHITESPACE%%>    @JoinColumn(name = "chemical_structure_id")),<br /><%%KEEPWHITESPACE%%>    @AssociationOverride(name = "pk.compound",<br /><%%KEEPWHITESPACE%%>    joinColumns =<br /><%%KEEPWHITESPACE%%>    @JoinColumn(name = "chem_compound_id"))})<br />public class ChemicalCompoundComposition implements Serializable {<br /><br /><%%KEEPWHITESPACE%%>    private ChemicalCompoundCompositionID pk = new ChemicalCompoundCompositionID();<br /><%%KEEPWHITESPACE%%>    private Double percentage;<br /><br /><%%KEEPWHITESPACE%%>    @EmbeddedId<br /><%%KEEPWHITESPACE%%>    public ChemicalCompoundCompositionID getPk() {<br /><%%KEEPWHITESPACE%%>        return pk;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    public void setPk(ChemicalCompoundCompositionID pk){<br /><%%KEEPWHITESPACE%%>        this.pk = pk;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    @Transient<br /><%%KEEPWHITESPACE%%>    public ChemicalCompound getCompound(){<br /><%%KEEPWHITESPACE%%>        return pk.getCompound();<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    public void setCompound(ChemicalCompound compound){<br /><%%KEEPWHITESPACE%%>       pk.setCompound(compound);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    @Transient<br /><%%KEEPWHITESPACE%%>    public ChemicalStructure getChemicalStructure(){<br /><%%KEEPWHITESPACE%%>        return pk.getChemicalStructure();<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    public void setChemicalStructure(ChemicalStructure structure){<br /><%%KEEPWHITESPACE%%>       pk.setChemicalStructure(structure);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @return the percentage<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    @Column(name = "percentage", nullable = false)<br /><%%KEEPWHITESPACE%%>    public Double getPercentage() {<br /><%%KEEPWHITESPACE%%>        return percentage;<br /><%%KEEPWHITESPACE%%>    }<br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * @param percentage the percentage to set<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public void setPercentage(Double percentage) {<br /><%%KEEPWHITESPACE%%>        this.percentage = percentage;<br /><%%KEEPWHITESPACE%%>    }<br />}<br /><br />

ChemicalCompoundCompositionID

<br />package org.bitbucket.kienerj.moleculedatabaseframework.entityclasses;<br /><br />import java.io.Serializable;<br />import javax.persistence.Embeddable;<br />import javax.persistence.ManyToOne;<br /><br />@Embeddable<br />public class ChemicalCompoundCompositionID implements Serializable {<br /><br /><%%KEEPWHITESPACE%%>    private ChemicalCompound compound;<br /><%%KEEPWHITESPACE%%>    private ChemicalStructure chemicalStructure;<br /><br /><%%KEEPWHITESPACE%%>    @ManyToOne(fetch = FetchType.LAZY)<br /><%%KEEPWHITESPACE%%>    public ChemicalCompound getCompound() {<br /><%%KEEPWHITESPACE%%>        return compound;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void setCompound(ChemicalCompound compound) {<br /><%%KEEPWHITESPACE%%>        this.compound= compound;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    @ManyToOne(fetch = FetchType.LAZY)<br /><%%KEEPWHITESPACE%%>    public ChemicalStructure getChemicalStructure() {<br /><%%KEEPWHITESPACE%%>        return chemicalStructure;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void setChemicalStructure(ChemicalStructure structure) {<br /><%%KEEPWHITESPACE%%>        this.chemicalStructure = structure;<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

As you can see this is far more complex than you would have imaged. We also need to create an entity (ChemicalCompoundComposition) that has no real meaning in the real world and for each compound you will create you will have to create as many ChemicalCompoundComposition instances as the compound contains substances. Note that fetch = FetchType.LAZY is absolutely required in the @Embeddable ID because else session.merge(chemicalCompound) will lead to a StackOverflowError (endless references).

The Data Access Objects

Now we need to create the layer that actually persists the entities to the database. To create that layer I followed the design outlined in The Persistence Layer with Spring 3.1 and Hibernate. We create a generic abstract class AbstractHibernateDAO that contains the basic database operations. The concrete classes are very simple as the only point of them is to specify which type of Entity they save. Of course you can add methods or override some if required.

AbstractHibernateDAO

The important part are the annotations @Repository, @Transactional and @Autowired

<br />package org.bitbucket.kienerj.moleculedatabaseframework.dao;<br /><br />import com.google.common.base.Preconditions;<br />import java.io.Serializable;<br />import java.util.List;<br />import org.hibernate.Session;<br />import org.hibernate.SessionFactory;<br />import org.springframework.beans.factory.annotation.Autowired;<br />import org.springframework.stereotype.Repository;<br />import org.springframework.transaction.annotation.Transactional;<br /><br />@Repository<br />@Transactional<br />public abstract class AbstractHibernateDAO&lt; T extends Serializable&gt; {<br /><br /><%%KEEPWHITESPACE%%>    private final Class&lt; T&gt; clazz;<br /><%%KEEPWHITESPACE%%>    @Autowired<br /><%%KEEPWHITESPACE%%>    SessionFactory sessionFactory;<br /><br /><%%KEEPWHITESPACE%%>    public AbstractHibernateDAO(final Class&lt; T&gt; clazzToSet) {<br /><%%KEEPWHITESPACE%%>        this.clazz = clazzToSet;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public T getById(final Long id) {<br /><%%KEEPWHITESPACE%%>        Preconditions.checkArgument(id != null);<br /><%%KEEPWHITESPACE%%>        return (T) this.getCurrentSession().get(this.clazz, id);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public List&lt; T&gt; getAll() {<br /><%%KEEPWHITESPACE%%>        return this.getCurrentSession()<br /><%%KEEPWHITESPACE%%>                .createQuery("from " + this.clazz.getName()).list();<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void create(final T entity) {<br /><%%KEEPWHITESPACE%%>        Preconditions.checkNotNull(entity);<br /><%%KEEPWHITESPACE%%>        this.getCurrentSession().persist(entity);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void update(final T entity) {<br /><%%KEEPWHITESPACE%%>        Preconditions.checkNotNull(entity);<br /><%%KEEPWHITESPACE%%>        this.getCurrentSession().merge(entity);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void delete(final T entity) {<br /><%%KEEPWHITESPACE%%>        Preconditions.checkNotNull(entity);<br /><%%KEEPWHITESPACE%%>        this.getCurrentSession().delete(entity);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void deleteById(final Long entityId) {<br /><%%KEEPWHITESPACE%%>        final T entity = this.getById(entityId);<br /><%%KEEPWHITESPACE%%>        Preconditions.checkState(entity != null);<br /><%%KEEPWHITESPACE%%>        this.delete(entity);<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public void setSessionFactory(SessionFactory sessionFactory) {<br /><%%KEEPWHITESPACE%%>        this.sessionFactory = sessionFactory;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    protected final Session getCurrentSession() {<br /><%%KEEPWHITESPACE%%>        return this.sessionFactory.getCurrentSession();<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

ChemicalStructureDAO

<br />package org.bitbucket.kienerj.moleculedatabaseframework.dao;<br /><br />import org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalStructure;<br />import org.springframework.stereotype.Repository;<br /><br />@Repository<br />public class ChemicalStructureDAO extends AbstractHibernateDAO {<br /><br /><%%KEEPWHITESPACE%%>    public ChemicalStructureDAO() {<br /><%%KEEPWHITESPACE%%>        super(ChemicalStructure.class);<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

ChemicalCompoundDAO

<br />package org.bitbucket.kienerj.moleculedatabaseframework.dao;<br /><br />import org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalCompound;<br />import org.springframework.stereotype.Repository;<br /><br />@Repository<br />public class ChemicalCompoundDAO extends AbstractHibernateDAO{<br /><br /><%%KEEPWHITESPACE%%>    public ChemicalCompoundDAO() {<br /><%%KEEPWHITESPACE%%>        super(ChemicalCompound.class);<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

The Spring configuration file

I had the most trouble with this. Keep in mind that this highly depends on what dependencies you plan on using, eg. witch database, connection pool or not and so forth. The configuration I use is for PostgreSQL using BoneCP connection pool. The configuration for BoneCP was taken from the BoneCP web page. The spring configuration file is under src/main/resources/ApplicationContext.xml. See the comments within the file.

<br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;beans xmlns="http://www.springframework.org/schema/beans"<br /><%%KEEPWHITESPACE%%>       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /><%%KEEPWHITESPACE%%>       xmlns:aop="http://www.springframework.org/schema/aop"<br /><%%KEEPWHITESPACE%%>       xmlns:context="http://www.springframework.org/schema/context"<br /><%%KEEPWHITESPACE%%>       xmlns:tx="http://www.springframework.org/schema/tx"<br /><br /><%%KEEPWHITESPACE%%>       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br /><%%KEEPWHITESPACE%%>          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd<br /><%%KEEPWHITESPACE%%>          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd<br /><%%KEEPWHITESPACE%%>          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd<br />"&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire="autodetect"&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="dataSource" ref="dataSource" /&gt;<br /><%%KEEPWHITESPACE%%>        &lt;!-- Don't forget to list all your entity classes here --&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="annotatedClasses"&gt;<br /><%%KEEPWHITESPACE%%>            &lt;list&gt;<br /><%%KEEPWHITESPACE%%>                &lt;value&gt;org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalStructure&lt;/value&gt;<br /><%%KEEPWHITESPACE%%>                &lt;value&gt;org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalCompound&lt;/value&gt;<br /><%%KEEPWHITESPACE%%>                &lt;value&gt;org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition&lt;/value&gt;<br /><%%KEEPWHITESPACE%%>            &lt;/list&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/property&gt;<br /><br /><%%KEEPWHITESPACE%%>        &lt;property name="hibernateProperties"&gt;<br /><%%KEEPWHITESPACE%%>            &lt;props&gt;<br /><%%KEEPWHITESPACE%%>                &lt;prop key="hibernate.dialect"&gt;org.hibernate.dialect.PostgreSQLDialect&lt;/prop&gt;<br /><%%KEEPWHITESPACE%%>                &lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt;<br /><%%KEEPWHITESPACE%%>                &lt;prop key="hibernate.hbm2ddl.auto"&gt;create&lt;/prop&gt;<br /><%%KEEPWHITESPACE%%>            &lt;/props&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/property&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/bean&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;!-- Spring bean configuration. Tell Spring to bounce off BoneCP --&gt;<br /><%%KEEPWHITESPACE%%>    &lt;bean id="dataSource"<br /><%%KEEPWHITESPACE%%>          class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="targetDataSource"&gt;<br /><%%KEEPWHITESPACE%%>            &lt;ref local="mainDataSource" /&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/property&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/bean&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;!-- BoneCP configuration --&gt;<br /><%%KEEPWHITESPACE%%>    &lt;bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="driverClass" value="org.postgresql.Driver" /&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="jdbcUrl" value="jdbc:postgresql:MolDB" /&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="username" value="postgres"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="password" value="123456"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="idleConnectionTestPeriod" value="60"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="idleMaxAge" value="240"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="maxConnectionsPerPartition" value="60"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="minConnectionsPerPartition" value="20"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="partitionCount" value="3"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="acquireIncrement" value="10"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="statementsCacheSize" value="50"/&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="releaseHelperThreads" value="3"/&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/bean&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;bean id="txManager"<br /><%%KEEPWHITESPACE%%>          class="org.springframework.orm.hibernate4.HibernateTransactionManager"&gt;<br /><%%KEEPWHITESPACE%%>        &lt;property name="sessionFactory" ref="sessionFactory" /&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/bean&gt;<br /><%%KEEPWHITESPACE%%>    &lt;tx:annotation-driven transaction-manager="txManager" /&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;context:annotation-config /&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;!-- Note the usage of abstract="true" and parent="AbstractHibernateDAO" in the implementations--&gt;<br /><%%KEEPWHITESPACE%%>    &lt;bean id="AbstractHibernateDAO" abstract="true"<br /><%%KEEPWHITESPACE%%>          class="org.bitbucket.kienerj.moleculedatabaseframework.dao.AbstractHibernateDAO"/&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;bean id="ChemicalStructureDAO" parent="AbstractHibernateDAO"<br /><%%KEEPWHITESPACE%%>          class="org.bitbucket.kienerj.moleculedatabaseframework.dao.ChemicalStructureDAO"/&gt;<br /><%%KEEPWHITESPACE%%>    &lt;bean id="ChemicalCompoundDAO" parent="AbstractHibernateDAO"<br /><%%KEEPWHITESPACE%%>          class="org.bitbucket.kienerj.moleculedatabaseframework.dao.ChemicalCompoundDAO"/&gt;<br />&lt;/beans&gt;<br />

More Configuration: Maven pom.xml

<br />&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /><%%KEEPWHITESPACE%%>  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;<br /><%%KEEPWHITESPACE%%>    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;groupId&gt;org.bitbucket.kienerj&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>    &lt;artifactId&gt;MoleculeDatabaseFramework&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>    &lt;version&gt;0.1-SNAPSHOT&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>    &lt;packaging&gt;jar&lt;/packaging&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;name&gt;MoleculeDatabaseFramework&lt;/name&gt;<br /><%%KEEPWHITESPACE%%>    &lt;url&gt;http://maven.apache.org&lt;/url&gt;<br /><%%KEEPWHITESPACE%%>    &lt;build&gt;<br /><%%KEEPWHITESPACE%%>        &lt;plugins&gt;<br /><%%KEEPWHITESPACE%%>            &lt;plugin&gt;<br /><%%KEEPWHITESPACE%%>                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>                &lt;version&gt;2.3.2&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>                &lt;configuration&gt;<br /><%%KEEPWHITESPACE%%>                    &lt;source&gt;1.7&lt;/source&gt;<br /><%%KEEPWHITESPACE%%>                    &lt;target&gt;1.7&lt;/target&gt;<br /><%%KEEPWHITESPACE%%>                    &lt;showDeprecation&gt;true&lt;/showDeprecation&gt;<br /><%%KEEPWHITESPACE%%>                &lt;/configuration&gt;<br /><%%KEEPWHITESPACE%%>            &lt;/plugin&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/plugins&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/build&gt;<br /><%%KEEPWHITESPACE%%>    &lt;properties&gt;<br /><%%KEEPWHITESPACE%%>        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/properties&gt;<br /><br /><%%KEEPWHITESPACE%%>    &lt;dependencies&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;junit&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;junit&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;3.8.1&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>            &lt;scope&gt;test&lt;/scope&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;org.springframework&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;spring-orm&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;3.1.2.RELEASE&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;4.1.7.Final&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;com.jolbox&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;bonecp-provider&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;0.8.0-alpha1&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;postgresql&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;postgresql&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;9.1-901.jdbc4&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>        &lt;dependency&gt;<br /><%%KEEPWHITESPACE%%>            &lt;groupId&gt;cglib&lt;/groupId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;artifactId&gt;cglib&lt;/artifactId&gt;<br /><%%KEEPWHITESPACE%%>            &lt;version&gt;2.2.2&lt;/version&gt;<br /><%%KEEPWHITESPACE%%>        &lt;/dependency&gt;<br /><%%KEEPWHITESPACE%%>    &lt;/dependencies&gt;<br />&lt;/project&gt;<br />

You need BoneCP-0.8.0-alpha1 for Hibernate 4! The release version does not work. This was also one of the many issues i had to figure out (thanks google). Maybe other connection pools have similar issues.

How to use

<br />package org.bitbucket.kienerj.moleculedatabaseframework;<br /><br />import org.bitbucket.kienerj.moleculedatabaseframework.dao.ChemicalCompoundDAO;<br />import org.bitbucket.kienerj.moleculedatabaseframework.dao.ChemicalStructureDAO;<br />import org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalCompound;<br />import org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition;<br />import org.bitbucket.kienerj.moleculedatabaseframework.entityclasses.ChemicalStructure;<br />import org.springframework.context.ApplicationContext;<br />import org.springframework.context.support.ClassPathXmlApplicationContext;<br /><br />public class App<br />{<br /><%%KEEPWHITESPACE%%>    public static void main( String[] args )<br /><%%KEEPWHITESPACE%%>    {<br /><br /><%%KEEPWHITESPACE%%>        // Yes,  I should now and then actually read manuals and documentations (=boring) but then<br /><%%KEEPWHITESPACE%%>        // I only have so much time and examples help me so much more<br /><%%KEEPWHITESPACE%%>        // THIS IS THE IMPORTANT LINE I DID NOT SEE IN ANY TUTORIAL<br /><%%KEEPWHITESPACE%%>        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");<br /><br /><%%KEEPWHITESPACE%%>        // You need to create the DAOs from Spring Context else the "Spring magic" will not be available<br /><%%KEEPWHITESPACE%%>        ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");<br /><%%KEEPWHITESPACE%%>        ChemicalCompoundDAO compoundDAO = (ChemicalCompoundDAO) context.getBean("ChemicalCompoundDAO");<br /><br /><%%KEEPWHITESPACE%%>        // From here on it is pretty straight forward.<br /><%%KEEPWHITESPACE%%>        // For me there are a bit too many lines to make it look nice but it works...<br /><%%KEEPWHITESPACE%%>        ChemicalStructure structure1 = new ChemicalStructure();<br /><%%KEEPWHITESPACE%%>        structure1.setStructureKey("c1ccccc1");<br /><%%KEEPWHITESPACE%%>        structure1.setStructureData("c1ccccc1");<br /><br /><%%KEEPWHITESPACE%%>        ChemicalStructure structure2 = new ChemicalStructure();<br /><%%KEEPWHITESPACE%%>        structure2.setStructureKey("CC=O");<br /><%%KEEPWHITESPACE%%>        structure2.setStructureData("CC=O");<br /><br /><%%KEEPWHITESPACE%%>        structureDAO.create(structure1);<br /><%%KEEPWHITESPACE%%>        structureDAO.create(structure2);<br /><br /><%%KEEPWHITESPACE%%>        ChemicalCompound compound = new ChemicalCompound();<br /><%%KEEPWHITESPACE%%>        compound.setCompoundName("Test Compound");<br /><br /><%%KEEPWHITESPACE%%>        ChemicalCompoundComposition composition1 = new ChemicalCompoundComposition();<br /><%%KEEPWHITESPACE%%>        composition1.setCompound(compound);<br /><%%KEEPWHITESPACE%%>        composition1.setChemicalStructure(structure1);<br /><%%KEEPWHITESPACE%%>        composition1.setPercentage(70.0);<br /><br /><%%KEEPWHITESPACE%%>        ChemicalCompoundComposition composition2 = new ChemicalCompoundComposition();<br /><%%KEEPWHITESPACE%%>        composition2.setCompound(compound);<br /><%%KEEPWHITESPACE%%>        composition2.setChemicalStructure(structure2);<br /><%%KEEPWHITESPACE%%>        composition2.setPercentage(30.0);<br /><br /><%%KEEPWHITESPACE%%>        compound.getComposition().add(composition1);<br /><%%KEEPWHITESPACE%%>        compound.getComposition().add(composition2);<br /><br /><%%KEEPWHITESPACE%%>        compoundDAO.create(compound);<br /><%%KEEPWHITESPACE%%>    }<br />}<br />

After running above snippet the database looks like this:

Conclusion

I hope this article can help some people to do their first steps with Spring and Hibernate. After all it is not hard if you know how it works..if…

UPDATE 1

You will need to watch out for LazyInitializationException. With above code of you call compound.getComposition().get(0).getChemicalStructure() (eg. get the first ChemicalStructure linked to this compound) outside of the DAO, meaning Hibernate Session is closed, you will get a LazyInitializationException. This happens because the data for the ChemicalStructure was not loaded (FetchType.LAZY) when loading the compound. To avoid this you will need to explicitly load the data within the DAO (Hibernate Session). Example

<br /><%%KEEPWHITESPACE%%>    public ChemicalCompound getById(Long id) {<br /><br /><%%KEEPWHITESPACE%%>        ChemicalCompound compound = compoundDAO.getById(id);<br /><%%KEEPWHITESPACE%%>        for (ChemicalCompoundComposition composition : compound.getComposition()) {<br /><%%KEEPWHITESPACE%%>            composition.getChemicalStructure().getId();<br /><%%KEEPWHITESPACE%%>        }<br /><%%KEEPWHITESPACE%%>        return compound;<br /><%%KEEPWHITESPACE%%>    }<br />

UPDATE Sep 2013

Above example of a many-to-many relationship with an additional column, namely ChemicalCompoundComposition can be achieved much easier and this easier solution is also more flexible especially in terms up updating. The solution is actually pretty obvious. No idea why I did not see it back then. Rookie mistake. Below the new code, with JPA 2.0 annotations and using project lombok annotations for auto generation of getters, setters and equals() and hashCode() methods.

<br />@Entity<br />@Table(name = "compound_composition", uniqueConstraints=<br /><%%KEEPWHITESPACE%%>        @UniqueConstraint(columnNames = {"chem_compound_id", "chemical_structure_id"}))<br />@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")<br />@Data<br />@EqualsAndHashCode(callSuper = false, of = {"compound", "chemicalStructure"})<br />public class ChemicalCompoundComposition extends BaseEntity {<br /><br /><%%KEEPWHITESPACE%%>    @Id<br /><%%KEEPWHITESPACE%%>    @GeneratedValue(strategy = GenerationType.AUTO,<br /><%%KEEPWHITESPACE%%>            generator = "composition_seq_gen")<br /><%%KEEPWHITESPACE%%>    @SequenceGenerator(name = "composition_seq_gen",<br /><%%KEEPWHITESPACE%%>            sequenceName = "seq_compound_composition", allocationSize = 1000)<br /><%%KEEPWHITESPACE%%>    @Column(name = "composition_id")<br /><%%KEEPWHITESPACE%%>    private Long id;<br /><br /><%%KEEPWHITESPACE%%>    @Column(name = "percentage")<br /><%%KEEPWHITESPACE%%>    private Double percentage;<br /><br /><%%KEEPWHITESPACE%%>    @JoinColumn(name = "chem_compound_id", nullable = false)<br /><%%KEEPWHITESPACE%%>    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})<br /><%%KEEPWHITESPACE%%>    private ChemicalCompound compound;<br /><%%KEEPWHITESPACE%%>    @JoinColumn(name = "chemical_structure_id", nullable = false)<br /><%%KEEPWHITESPACE%%>    @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})<br /><%%KEEPWHITESPACE%%>    private ChemicalStructure chemicalStructure;<br /><br /><%%KEEPWHITESPACE%%>    /**<br /><%%KEEPWHITESPACE%%>     * For JPA Provider<br /><%%KEEPWHITESPACE%%>     */<br /><%%KEEPWHITESPACE%%>    public ChemicalCompoundComposition() {<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    public ChemicalCompoundComposition(ChemicalCompound compound,<br /><%%KEEPWHITESPACE%%>            ChemicalStructure structure,<br /><%%KEEPWHITESPACE%%>            Double percentage) {<br /><br /><%%KEEPWHITESPACE%%>        this.percentage = percentage;<br /><%%KEEPWHITESPACE%%>        this.chemicalStructure = structure;<br /><%%KEEPWHITESPACE%%>        this.compound = compound;<br /><%%KEEPWHITESPACE%%>    }<br />}<br />
Advertisements

Written by kienerj

October 5, 2012 at 16:38

Posted in Database, Java, Programming

Tagged with , ,

6 Responses

Subscribe to comments with RSS.

  1. Hi,
    I am new here , this is a nice tutorial, can you please post the source code with a sample database ?
    thanks, your help is appreciated.

    Yahaya Bentaleb

    April 26, 2013 at 17:29

    • The source code is in the post. Not sure what you are looking for exactly? I let hibernate generate the database (see the entry in the spring configuration file create)

      kienerj

      April 29, 2013 at 12:43

  2. Reblogged this on Srikanth's Blog.

    srikanth ganta

    March 6, 2013 at 10:02

  3. Hi, your post was very helpfull so I will try to get your help once more 🙂
    I used the same structure you used so I could build a many to many relationship for my software. However, I am stucked in a problem: the table built has a primary composed key that I do not want.
    My “linker class” is a historical table, keeping records of products that comes in and goes out, who send/took the product, with extra records of who registered the operation, and the time and date. So, whenever a person takes a product that he/she already took in the past, hibernate complains because the composed key is already in the table. Is there a way to use the solution you proposed without generating this primary composed key in the database?
    Thanks

    Ricardo Sartori

    November 22, 2012 at 07:14

    • Disclaimer: I’m new at this too so you might ask for advice other where (like stackoverflow) too.

      As far as I can tell you need a different approach. I think you don’t actually have a man-to-many relation. Create an normal entity class for the historical table that has an id column, all the other fields and the mappings.

      kienerj

      November 22, 2012 at 15:57


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: