Category Archives: Java

Hibernate annotation to the rescue when mapping files cannot be located

Forget hibernate mapping files, seriously unless you really need to. Use annotations instead. Then you need not worry about running into class path issues.

This is the story:

I wanted to create a simple RESTFul service which exposes simple CRUD functionality on data within a PostgreSQL database. In a previous post,
I briefly covered using Hibernate to connect to a PostgreSQL database to retrieve entities within the context of a RESTful webservice. This all worked flawlessly since the deployment target was IntelliJ’s embedded http server. When it came time to deploy the resulting .war to a local Tomcat instance, all hell broke loose.

I used the the Jersey archetype for Maven which gave provided a directory structure like this:

|- src
   |- main
      |- java
         |-my-app
            - User.java
            - HibernateUtils.java
            .......
      |- resources
          - hibnernate.cfg.xml
          - user.hbm.xml

As stated earlier, everything worked as expected when deployed to IntellJ’s local http server. However, when .war file was deployed to a local Tomcat instance on the same box, hibernate was not able to find a mapping for the user entity. The error was

User is not mapped [from User where id > :id]

for a class defined as follows:

public class User {
    private int id;
    private String _firstName;
    private String _lastName;

    public String getFirstName(){
        return _firstName;
    }
    public void setFirstName(String name){
        _firstName = name;
    }

    public int getId() {
        return id;
    }

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

    public String getLastName() {
        return _lastName;
    }

    public void setLastName(String _lastName) {
        this._lastName = _lastName;
    }

    @Override public String toString(){
        return String.format("%s %s", _firstName, _lastName);
    }
}

The hibernate files were all in place and mappings were all correct. After spending a couple of days and not seemingly getting anywhere, questioning my sanity, I decided on another approach: annotations. After all, this is the common pattern when using the Entity Framework in .NET.

The User class was modified as follows:

import javax.persistence.*;

/**
 * Created by Klaus on 31/08/2015.
 */
@Entity
@Table( name = "users" )
public class User {

    @Id
    @GeneratedValue
    private int id;

    @Column (name = "firstname")
    private String _firstName;

    @Column (name = "lastname")
    private String _lastName;

    /* rest of code ignored for brevity */
}

HibernateUtils was also modified:

public class HibernateUtils {
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {

        if (sessionFactory == null) {
            // loads configuration and mappings
            Configuration configuration =
                    new Configuration()
                            .addAnnotatedClass(User.class)
                            .configure();

            ServiceRegistry serviceRegistry
                    = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).build();

            // builds a session factory from the service registry
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        }

        return sessionFactory;
    }

Repacking, deploying to IntelliJ’s local http server ensured functionality was not broken. Next, deploying to a local instance of Tomcat on the local machine, also proved successful. This left me pondering for a while…. but there are things to get done…

What happened here remains a mystery which begs for an explanation. Could a unit test have saved me endless hours deploying to Tomcat?

Quick start on using Hibernate with Postgres 9.4 in IntelliJ

Preliminaries:
1. Install IntelliJ Ultimate. You can get a 30 day trial license.
2. Install PostgresSQL 9.4 or whatever is the latest version today.

What do do:
1. Create a new Maven Project in HIbernate. User the simplest maven archetype to get a good folder structure. I chose the maven-archetype-webapp archetype.
2. Right click on the newly created project and enable Hibernate support through the “Add Framework Support” menu.
3. Add Postgres 9.4 dependencies via Maven.
4. Launch PgAdmin and connect to your PostgreSQL database.
5. Create a users table in PostgresSQL using the following script:

create table Users (
   id SERIAL,
   firstName VARCHAR(100) default NULL,
   lastName  VARCHAR(100) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

6. Under the resources folder, add a new hibernate.cfg.xml file with the following content:

 <session-factory>

    <property name="dialect">org.hibernate.dialect.PostgreSQL82Dialect</property>
    <property name="connection.driver_class">org.postgresql.Driver</property>
    <property name="connection.url">jdbc:postgresql://localhost:5432/database</property>
    <property name="connection.username">username</property>
    <property name="connection.password">password</property>

    <property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <property name="current_session_context_class">thread</property>
    <property name="hibernate.show_sql">false</property>
  </session-factory>

7. In the same folder, add a users.hbm.xml file with the following content:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="tut.User" table="Users">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <id name="id" type="int" column="id">
            <generator class="increment"/>
        </id>
        <property name="firstName" column="firstname" type="string"/>
        <property name="lastName" column="lastname" type="string"/>
        <property name="age" column="age" type="int"/>
    </class>
</hibernate-mapping>

8. Create a new folder under src/main/java/myco/utils and create a new file HibernateUtils class to host your Session Factory as follows:

public class HibernateUtils {
    private static final SessionFactory ourSessionFactory;
    private static final ServiceRegistry serviceRegistry;

    static {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();

            serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
            ourSessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return ourSessionFactory.openSession();
    }
}

9. Create a new folder under src/main/java/myco/models and a new User class as follows:

public class User {
    private String _firstName;
    private String _lastName;
    private int _age;
    private boolean _isEmployed;
    private int _id;

    public String getFirstName(){
        return _firstName;
    }
    public void setFirstName(String name){
        _firstName = name;
    }

    public int getAge(){
        return _age;
    }
    public void setAge(int age){
        _age = age;
    }

    public boolean getIsEmployed(){
        return _isEmployed;
    }
    public void setIsEmployed(boolean isEmployed){
        _isEmployed = isEmployed;
    }
   
    public int getId() {
        return _id;
    }

    public void setId(int _id) {
        this._id = _id;
    }

    public String getLastName() {
        return _lastName;
    }

    public void setLastName(String _lastName) {
        this._lastName = _lastName;
    }

    @Override public String toString(){
        return String.format("%s Ss", _firstName, _age);
    }

}

10. Create a UserResource file under src/main/java/myco/resources as follows:


public class UserResource { 
    public User[] getAll(){

        Session session = HibernateUtils.getSession();
        session.beginTransaction();

        Query query=  session.createQuery("from User where  id > :id");
        query.setParameter("id", 0);

        Object[] users = query.list().toArray();

        User[] toReturn = new User[users.length];
        for (int i = 0; i < users.length; i++){
            toReturn[i] = (User)users[i];
        }

        session.close();
        return toReturn;
    }
 
    public User[] createUsers(User[] users){

        Session session = HibernateUtils.getSession();
        session.beginTransaction();

        for (User user : users){
            System.out.println("Adding user to session " + user.toString());
            session.save(user);
        }

        session.getTransaction().commit();
        session.close();

      return users;
    }
}

11. Create a UserResourceTest class under src/text/java/myco inheriting from TestCase as follows:

public class UserResourceTest extends TestCase {

    @org.junit.Test
    public void testGetAll() throws Exception {

        UserResource userResource = new UserResource();
        User[] users = userResource.getAll();

        Assert.assertTrue(users.length > 0);

    }

    @org.junit.Test
    public void testCreateUsers() throws Exception {

        User user = new User();
        user.setAge(100);
        user.setFirstName("James");
        user.setLastName("Bond");

        UserResource userResource = new UserResource();
        userResource.createUsers(new User[]{ user});

        Assert.assertTrue(user.getId() > 0);
    }
}

12. Go to View | Tools Windows | Maven Project to launch the Maven tools window.
13. Expand the project within the Maven tools window, right click on the clean life cycle and run it.
14. Unless I missed a step, you should see BUILD SUCCESS in your output window.
15. Right click on UserResourceTest and select Run UserResourceTest. Test should all run with green lights.

Happy Coding.