Sunday, 19 August 2018

No XML Spring and Hibernate Integration

Back in the pre Spring 3.1 days, we had to configure each and every bean into one of the spring configuration files which only happens to be an XML. And so if we were building a web application with Spring which is also using a relational database to store all its data, we needed to create a bean tag into one of those spring configuration XML files for reading out database connection properties to create a data source bean, which we then feed as a parameter to yet another bean tag to create a database session factory bean.
In this post we will be building a small restful web application with Spring MVC integrated with Hibernate to fetch the user record from MySQL database server and display it as a JSON response on the browser, without writing a single XML file. Furthermore we will also be doing away with tomcat’s web.xml leveraging latest Servlet 3.1 APIs and doing all of that configuration in our Java classes. So what are we waiting for!

Configuring Spring and Hibernate Integration

We can start by making a maven project with webapp archetype into any of our favourite IDE. And in its pom.xml file we can give all the dependencies as per this gist. Notice that as one of the properties we have to set failOnMissingWebXml to be false so that we can safely delete web.xml file.
Now we can start with configuring DispatcherServlet for our Spring MVC application which we can do in a single class:
public class AppConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Overrideprotected Class<?>[] getRootConfigClasses() {
    return new Class[] { HibernateConfig.class };
  }

  @Overrideprotected Class<?>[] getServletConfigClasses() {
    return new Class[] { WebMvcConfig.class };
  }

  @Overrideprotected String[] getServletMappings() {
    return new String[] { "/" };
  }

}
A couple of points to note here:
  • This class is extending the AbstractAnnotationConfigDispatcherServletInitializerwhich automatically configure DispatcherServlet and the Spring application context.
  • In getServletMappings() methods we return one or more paths that DispatcherServlet will be mapped to.
  • In getServletConfigClasses() we would be returning the @Configuration annotated classes that are having beans from which DispatcherServlet will be loading its application context.
  • Classes returned from getRootConfigClasses() will be used to configure other application contexts that are created by ContextLoaderListener and are shared among them.
This is all we need to configure our DispatcherServlet, now let's look into HibernateConfig.java and WebMvcConfig.java. In HibernateConfig.java we need to create all the beans that are necessary for handling interaction with database via Hibernate:
@Configuration
@EnableTransactionManagement
public class HibernateConfig {

  @Beanpublic LocalSessionFactoryBean getSessionFactory() throws PropertyVetoException {
    LocalSessionFactoryBean bean = new LocalSessionFactoryBean();

    Properties hibernateProperties = new Properties();
    hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
    hibernateProperties.put("hibernate.show_sql", "true");

    bean.setHibernateProperties(hibernateProperties);
    bean.setDataSource(getDataSource());
    bean.setPackagesToScan("com.spring5.app.dto");
    return bean;
  }

  @Beanpublic ComboPooledDataSource getDataSource() throws PropertyVetoException {
    ComboPooledDataSource dataSource = new ComboPooledDataSource();

    dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/app-db?useSSL=false");
    dataSource.setUser("root");
    dataSource.setPassword("qwerty123");
    dataSource.setAcquireIncrement(10);
    dataSource.setIdleConnectionTestPeriod(0);
    dataSource.setInitialPoolSize(5);
    dataSource.setMaxIdleTime(0);
    dataSource.setMaxPoolSize(50);
    dataSource.setMaxStatements(100);
    dataSource.setMinPoolSize(5);

    return dataSource;
  }

  @Beanpublic JdbcTemplate getJdbcTemplate() throws PropertyVetoException {
    JdbcTemplate template = new JdbcTemplate();     
    template.setDataSource(getDataSource());     
    return template;
  }

  @Beanpublic HibernateTransactionManager getTransactionManager() throws PropertyVetoException {
    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory(getSessionFactory().getObject());
    return transactionManager;
  }

}
In WebMvcConfig.java we need to create web specific beans, so as we are creating restful endpoints we would need appropriate message converters that would be required to convert Java objects to their proper JSON representations.
@Configuration
@EnableWebMvc
@ComponentScan("com.spring5.app")
public class WebMvcConfig extends WebMvcConfigurationSupport {

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(customJackson2HttpMessageConverter());
    super.addDefaultHttpMessageConverters(converters);
  }

  @Bean
  public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    jsonConverter.setObjectMapper(objectMapper);
    return jsonConverter;
  }

}

Implementing REST and Persistence Layers

Now that we have configured all the important parts of our application we now need to implement a REST controller and corresponding Service and DAO that are quite straightforward.
@RestController()
@RequestMapping("user")
public class UserController {

  @Autowiredprivate UserService service;

  @RequestMapping(value = "{userId}", method = RequestMethod.GET)
  public @ResponseBody ServerResponse getUser(@PathVariable("userId") Long userId) {
    return this.service.getUser(userId);
  }
}
The data access object class:
@Repository
public class UserDaoImpl implements UserDao {
 
  @Autowiredprivate SessionFactory sessionFactory;

  @Overridepublic UserDTO getUser(Long userId) {
    TypedQuery<UserDTO> typedQuery = sessionFactory.getCurrentSession().createQuery("from UserDTO where id=" + userId.toString());
    return typedQuery.getSingleResult();
  }

}
And finally our service class is doing some mission critical stuff!
@Service
public class UserServiceImpl implements UserService {

  @Autowiredprivate UserDao userDao;

  @Override@Transactional(readOnly = true)
  public ServerResponse getUser(Long userId) {
    ServerResponse response = new ServerResponse();

    UserDTO dto = userDao.getUser(userId);
    response.setUser(new User(dto.getFirstName() + " " + dto.getLastName(), 
                        new Long(dto.getAge())));

    return response;
  }

}

Database schema

Lastly for the application to work we also need to create database schema in our MySQL server:
create table if not exists `users` (
  `id`  int not null auto_increment,
  `firstName` varchar(20),
  `lastName` varchar(20),
  `age`  int,
  primary key (`id`)
);
insert into `users` values (1, "john", "doe", 29);

Source Code

I have not put all of the code on this post, but you can check out the working project from this github repository

Embedded H2 Database with Spring Boot Application

It’s a well known fact that when we are building a web application it is nearly impossible to do away with some form of data storage. There's got to be a database, relational or non-relational, where we need to store the business data to be retrieved and used later. Desktop applications too might require some useful data to be be stored locally like application settings, cached data from servers etc.
H2 is one of the lightweight and open source relational database management system written in java and can be easily embedded in java applications or run in client server mode. In this post we are going to use H2 database embedded in a Spring Boot application. And for the sake simplicity we will only creating a dummy application setting record on out embedded H2 database and then retrieving the same record. So let’s begin!

Setting up Spring Boot project

Setting up a Spring Boot project is quite easy. Head to Spring Initializr website and fill in the appropriate details on left under “Project Metadata”. Under “Dependencies” fill in H2 and JPA as dependencies and hit “Generate Project”. This will download a preconfigured spring boot project that we can open with our favourite IDE.
Once we have our initial project setup with IDE, we can start adding more details on it.

Adding JPA Repository and Entity

Next up is adding database Entity and corresponding Spring Data JPA Repository to do CRUD operation on that repository. Since we have decided to save application settings into embedded H2 database we would need to create an entity class for Application Settings.
package com.jeetprksh.h2.boot.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class ApplicationSetting {

    @Id@GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String userEmail;
    private boolean cachingEnabled;

    ApplicationSetting() {

    }

    public ApplicationSetting(String userEmail, boolean cachingEnabled) {
        this.userEmail = userEmail;
        this.cachingEnabled = cachingEnabled;
    }

    @Overridepublic String toString() {
        return "ApplicationSetting{" +
                "id=" + id +
                ", userEmail='" + userEmail + '\'' +
                ", cachingEnabled=" + cachingEnabled +
                '}';
    }
}
And declare a Spring Data Repository interface.
package com.jeetprksh.h2.boot.dao;

import com.jeetprksh.h2.boot.entity.ApplicationSetting;
import org.springframework.data.repository.CrudRepository;

public interface AppSettingRepository extends CrudRepository<ApplicationSetting, Integer> {
}
Now we need to Autowire this repository and do the saving and fetching of application settings.
package com.jeetprksh.h2.boot.app;

import com.jeetprksh.h2.boot.dao.AppSettingRepository;
import com.jeetprksh.h2.boot.entity.ApplicationSetting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.logging.Logger;

@SpringBootApplication(scanBasePackages = "com.jeetprksh.h2.boot")
@EnableJpaRepositories("com.jeetprksh.h2.boot")
@EntityScan("com.jeetprksh.h2.boot")
public class Application {

    private static Logger logger = Logger.getLogger(Application.class.getName());

 @Autowired
 private static AppSettingRepository repository;

 public static void main(String[] args) {
  SpringApplication.run(Application.class, args);
  repository.save(new ApplicationSetting("abc@def.ghi", true));
  repository.findAll().forEach(setting -> {
            logger.info(setting.toString());
        });
 }

 @Autowired
 public void setRepository(AppSettingRepository repository) {
  Application.repository = repository;
 }
}
Note: I decided to add/retrieve the settings in the configuration file itself, but it would have been better off in an appropriate service.

Setting Application Properties

Our application would require following properties:
# Datasource
spring.datasource.url=jdbc:h2:file:~/embedded-db
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

# JPA
spring.jpa.hibernate.ddl-auto=update
  • Spring.datasource.url : Here we give the connection URL to the database. Since we are using embedded H2 database which saves all of its data in local file system we will be giving in the path to the file which will be used to store data. In our case this file will be in user’s home directory.
  • Spring.datasource.username : The user name for H2 database.
  • Spring.datasource.password : Password for database, by default it does not have one.
  • Spring.datasource.driver-class-name : The driver class that would be used.
  • Spring.jpa.hibernate.ddl-auto : Setting this property to “update” will enable application to use existing database and not drop the database on each startup.

Running the Project

There are numerous ways to run a spring boot project. Let’s do it with creating executable jar with maven, following commands would do it:
mvn package
cd .\target\
java -jar .\h2-springboot-embedded-0.0.1-SNAPSHOT.jar
Notice that after running this application a file will be created in user home directory with name embedded-db.mv.db which will be having our database schema and all the records we will be saving into it.

Code

All the working code for this project is available on this github repository.

Useful Links