<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d8334277\x26blogName\x3dSriram\x27s+Blog\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLUE\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttps://metallicatony.blogspot.com/search\x26blogLocale\x3den\x26v\x3d2\x26homepageUrl\x3dhttp://metallicatony.blogspot.com/\x26vt\x3d6147907796332168684', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>

Wednesday, April 03, 2013

CRUD using Java, Spring, Hibernate, Maven and Log4J

This post illustrates how to integrate Spring into a simple java project and how that in turn simplifies and paves way for an effective coding approach. This project is similar to the previous one CRUD with Java, Hibernate and Maven for the most part. The one big difference is that this project uses Spring in addition to the first one to demonstrate how the application code can be further simplified, modularized and can be more organized and structured. This was possible because Spring framework takes the responsibility of instantiating the required beans, autowiring and injecting the needed dependencies, managing the lifecycle of instantiated beans and it takes care of database sessions and transactions too. By using Spring, much of the boiler plate redundant code is removed and thus simplified. I tried to follow the same design patterns that were used in previous project.
Software Used
1) Java 1.6
2) Spring Tool suite (STS) 3.1.0
3) Spring framework 3.2.2
4) Oracle 11g Express Edition
5) Apache maven 3.0.4
6) Hibernate 4.1.8 Final
7) Log4j 1.2.16 and Slf4j 1.6.1

What's new in this project from the previous one?
a) Configuration and integration of Spring
b) Spring annotations - @Repository, @Component, @Service, @Transactional, @Autowired and component scanning
c) Hibernate annotations - One to many and Many to one, Fetch Types, Fetch modes
d) New tables EMPLOYEE_EXPENSE (which has the list of expenses for every employee) and DEPARTMENT (list of departments) are introduced

Pre-installation and validation steps
Installation and setup is exactly same like the previous project. An additional thing to do is – to create the new tables EMPLOYEE_EXPENSE and DEPARTMENTS and insert data. The below script was used for it

CREATE TABLE EMPLOYEE_EXPENSE
  (
    "EMP_EXP_ID"    NUMBER,
    "EMP_ID"        NUMBER(5,0),
    "YEAR"          NUMBER(4,0),
    "MONTH"         NUMBER(2,0),
    "EXPENSE_CLAIM" NUMBER(7,2),
    "APPROVED_AMT"  NUMBER(7,2),
    "PAID_DATE" DATE,
    CONSTRAINT "EMP_EXP_PK" PRIMARY KEY ("EMP_EXP_ID"), 
    CONSTRAINT "FK_EMPLOYEE" FOREIGN KEY ("EMP_ID") REFERENCES "EMPLOYEE" ("EMP_ID") ENABLE
  );

REM INSERTING INTO EMPLOYEE_EXPENSE
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (1,7369,2002,2,3072.43,3072.43,to_timestamp('03-MAR-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (2,7369,2002,4,30,30,to_timestamp('01-JUN-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (3,7369,2002,5,235.03,35.03,to_timestamp('01-JUN-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (4,7369,2002,9,5095.98,5095.08,to_timestamp('31-OCT-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (5,7369,2002,12,1001.01,1001.01,to_timestamp('01-FEB-03','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (6,7782,2002,1,111.09,111.09,to_timestamp('01-FEB-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (7,7782,2002,3,9.85,9.85,to_timestamp('01-APR-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (8,7782,2002,7,3987.32,3987.32,to_timestamp('01-AUG-02','DD-MON-RR HH.MI.SSXFF AM'));
INSERT INTO EMPLOYEE_EXPENSE (EMP_EXP_ID,EMP_ID,YEAR,MONTH,EXPENSE_CLAIM,APPROVED_AMT,PAID_DATE) VALUES (9,7782,2002,9,1200,1200,to_timestamp('01-OCT-02','DD-MON-RR HH.MI.SSXFF AM'));


CREATE TABLE DEPARTMENT
  (
    "DEPT_ID"     NUMBER(5,0) NOT NULL ENABLE,
    "NAME"        VARCHAR2(20 BYTE),
    "LOCATION_ID" NUMBER(3,0),
    CONSTRAINT "DEPARTMENT_PK" PRIMARY KEY ("DEPT_ID")
  );

REM INSERTING into DEPARTMENT
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (10,'ACCOUNTING',122);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (20,'RESEARCH',124);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (30,'SALES',null);
INSERT INTO DEPARTMENT (DEPT_ID,NAME,LOCATION_ID) values (40,'OPERATIONS',167);


Create maven project(pom.xml)
The one additional step that was done here is to add spring related configuration in pom.xml. This involves adding spring artifacts spring-orm and spring-context. Here is the complete pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.samples</groupId>
  <artifactId>associationMapper</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>associationMapper</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>3.2.2.RELEASE</spring.version>
    <hibernate.version>4.1.9.Final</hibernate.version>
    <oracle.version>11.2.0</oracle.version>
    <junit.version>4.11</junit.version>
    <commons-logging.version>1.1.1</commons-logging.version>
    <log4j.version>1.2.16</log4j.version>
    <slf4j.version>1.6.1</slf4j.version>
  </properties>

  <dependencies>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>${spring.version}</version>
 </dependency>
   <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${spring.version}</version>
 </dependency>
 <dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>${hibernate.version}</version>
 </dependency>
 <dependency>
  <groupId>com.oracle</groupId>
  <artifactId>ojdbc6</artifactId>
  <version>${oracle.version}</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
 </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

applicationContext.xml (src/main/resources)
This is the master configuration file that Spring reads to instantiate all needed beans. The filename can be anything.xml. It doesn’t matter. I have provided the entire contents of this spring bean config below. All it contains is the configuration for the beans that would be instantiated by Spring framework. The needed properties for every bean is provided so that it gets instantiated successfully. For example, to create a datasource bean, we need all the database related properties and so it is provided. But instead of providing all database connection properties inline, we are reading them using spring’s PropertyPlaceholderConfigurer class. By doing so, these property values can be used elsewhere in the config file using ${variable} notation. And doing this way could help us having the environment specific database properties easily swapped based on which environment (dev/qa/prod) the code is deployed. In our case, the property place holder uses the configurations from the file database.properties which is present in the class path (src/main/resources)

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:XE
jdbc.username=metallicatony
jdbc.password=xxx

Following the datasource configuration, comes the SessionFactory bean. To instantiate SessionFactory, we use the new LocalSessionFactoryBean class instead of the old AnnotationSessionFactoryBean class. SessionFactory bean needs datasource, hibernate properties and the list of annotated classes as properties. Using all these properties, Spring will be able to instantiate the hibernate sessionFactory bean which in turn will be used by the application code. In addition to that, we have the configuration for hibernate transaction manager and the definition which ensures that the application supports annotation based transactions.
 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
 </bean>
 <tx:annotation-driven transaction-manager="transactionManager" />
And the last and most important configuration that saves all our programmers lives is “component scan”!

Just imagine, if we were to define all the hundreds and thousands of (application) beans that we are using in an enterprise application to be defined for Spring!! Argh!! So, instead of defining every single bean in this config file, we ask Spring to scan and autodetect implementation classes using the annotations and instantiate beans through that. The classes that were declared with @Service (service layer beans), @Component(generic beans), @Repository (DAO layer beans) will be created as beans.

ApplicationMain.java 

In ApplicationMain class, the previously discussed applicationContext.xml is used by Spring's ClassPathXmlApplicationContext class to create the application context. This context will hold all the instantiated beans - beans from both applicationContext.xml and the beans that were instantiated through annotations.

Service Layer

From application coding perspective, I have added one more layer – yes, it’s the service layer. The ApplicationMain class calls this service layer from which the control passes down to BO layer, DAO layer and then to the domain layer. 

Here is the complete applicationContext.xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/context 
              http://www.springframework.org/schema/context/spring-context-3.0.xsd
              http://www.springframework.org/schema/tx 
              http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
              
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
 <property name="location">
  <value>database.properties</value>
 </property>
</bean>
 
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 <property name="driverClassName" value="${jdbc.driverClassName}" />
 <property name="url" value="${jdbc.url}" />
 <property name="username" value="${jdbc.username}" />
 <property name="password" value="${jdbc.password}" />
</bean>
 
 <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource">
      <ref bean="dataSource"/>
    </property>
 
    <property name="hibernateProperties">
       <props>
         <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
         <prop key="default_schema">METALLICATONY</prop>
         <prop key="hibernate.show_sql">true</prop>
       </props>
    </property>
 
    <property name="annotatedClasses">
 <list>
  <value>com.samples.domain.Employee</value>
  <value>com.samples.domain.Department</value>
  <value>com.samples.domain.EmployeeExpense</value>
 </list>
    </property>
 </bean>
 
 <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
 </bean>
 <tx:annotation-driven transaction-manager="transactionManager" />

 <context:component-scan base-package="com.samples"/>
</beans>

SessionFactory and Transactions
Please remember that as of Hibernate 3.0, there is no need of using HibernateTemplate. In the past, this was used to get a session factory object which in turn was used to get a session before every database transaction. This route is not taken these days and SessionFactory can be directly used to get a session object (sessionFactory.getCurrentSession())

Every DAO class will now have SessionFactory bean auto-injected like this

@Autowired 
SessionFactory sessionFactory;
using which we can get the current session to perform every database operation. Added to that, we now have @Transactional declaration
@Transactional(propagation=Propagation.REQUIRED)
on every method in the service layer (com.samples.service.impl) that does atleast one database operation. By doing that, we are trying to say that all db operations that happen in that method will be within a single transaction (a basic unit of work on a database). This annotation takes care of creating a new transaction and ending the transaction after the unit of work is complete. What really happened underneath was that the DAO method was intercepted and proxied inside a transaction before proceeding with the actual code that we have written!! Wheeee!! This kind of programming technique is called Aspect Oriented Programming (AOP). The transaction propagation (a parameter to the transactional annotation) is used to tell the behavior of a transaction. Propagation.REQUIRED says to continue the transaction if there was any before and to create a new transaction if there wasn’t any. 

One last thing that is new in this project is – Hibernate annotations for One to Many and Many to One. There are lot of confusions in internet about this. So let me clear this. Lets say if there is an EMPLOYEE table and for every employee there are many expenses in EMPLOYEE_EXPENSES table, then we say EMPLOYEE has ONE TO MANY relation to EMPLOYEE_EXPENSES. If the EMPLOYEE table has a department_id column and every employee will belong to one of the available departments in the DEPARTMENT table, then we say it’s a MANY (employees) TO ONE (department) relation using the foreign key column department_id in the EMPLOYEE table. 


It’s important to have @Join annotation on the property of the entity that holds the foreign key column. The entity on the other side of the relationship (parent table) will hold a Set property that can hold the list of the records from the foreign key (child) table. And that’s the reason, we have the below in EmployeeExpense.java
@ManyToOne
@JoinColumn(name="EMP_ID")
private Employee employee;
and the below in Employee.java
@OneToMany(mappedBy="employee", fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<EmployeeExpense> employeeExpenses;
In the same way, the Many to one relation between Employee and department is configured as follows. In Employee.java
@ManyToOne(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="DEPT_ID")
private Department department;
and in Department.java
@OneToMany(mappedBy="department")
private Set<Employee> employees;

Huh, did you notice the fetching strategy that was mentioned above? In hibernate, there are 2 FetchTypes – LAZY, EAGER and 3 FetchModes – SELECT, JOIN, SUBSELECT.LAZY and SELECT go together i.e when we get Employee record, it won't get the in-relation records - EmployeeExpense but would wait for its access to fetch. EAGER and JOIN or SUBSELECT go together i.e when we get Employee record, it would get the in-relation records using a JOIN or SUBSELECT SQL query. Here the associated data is EAGER fetched.


I hope this project gives anyone an overall idea about Spring, Hibernate, their integration and the various coding and configuration details that needs to be adapted for creating a better coding world!! Feel free to browse through or download the source from my git repository CRUD using Spring and Hibernate @ Github

Labels: ,