Using JBoss Transaction Manager in a Spring application

In this tutorial we will learn how to use JBoss Transaction Manager on the top of Spring’s transaction management abstractions.

The Spring framework allows pluggable transaction managers. However, iIf you need XA support for your Spring applications, then you need to plug in a transaction manager such as JBossTS.

Let’s see how to configure JBoss Transaction Manager in a sample application which executes Transaction Statements using Spring JDBCTemplate and the default JBoss/WildFly DataSource for H2 database.

Here is the simple Customer class which works as a model:

package com.sample;

public class Customer {

    private String name;
    private String surname;
    private int age;

    public Customer() {

    }

    public Customer(String name, String surname, int age) {
        this.name = name;
        this.surname = surname;
        this.age = age;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                '}';
    }
}

We will use a DAO interface to handle basic SQL Operations on the model:

package com.sample;
import java.util.List;


public interface JDBCCustomerDAO {

    public void insert(Customer customer);

    public List<Customer> findAll();

    public void createTable();
    public void dropTable();
}

Here is the DAO implementation, which contains a method tagger as @Transactional with the attribute REQUIRED:

package com.sample;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;


import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

public class JDBCCustomerDAOImpl implements JDBCCustomerDAO {
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void createTable() {
        jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate
                .execute("create table customer (name varchar, surname varchar, age integer)");
        System.out.println("Table created!");
    }

    public void dropTable() {
        jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.execute("drop table customer");
        System.out.println("Table dropped!");
    }
    @Transactional(propagation = Propagation.REQUIRED)
    public void insert(Customer customer) {

        String sql = "INSERT INTO CUSTOMER "
                + "(NAME,SURNAME, AGE) VALUES (?, ?, ?)";

        jdbcTemplate = new JdbcTemplate(dataSource);

        jdbcTemplate.update(sql,
                new Object[] { customer.getName(), customer.getSurname(),
                        customer.getAge() });
    }

    @SuppressWarnings("rawtypes")
    public List<Customer> findAll() {

        jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "SELECT * FROM CUSTOMER";

        List<Customer> customers = new ArrayList<Customer>();

        List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
        for (Map row : rows) {
            Customer customer = new Customer();
            customer.setSurname((String) row.get("SURNAME"));
            customer.setName((String) row.get("NAME"));
            customer.setAge(Integer.parseInt(String.valueOf(row.get("AGE"))));
            customers.add(customer);
        }

        return customers;
    }

}

As soon as the Spring application is deployed, we will trigger the SQL Statements. For this purpose, we can deploy a WebListener which is fired when the application is deployed and undeployed:

package com.sample;


import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.List;

@WebListener
public class MyContextListener implements ServletContextListener {
    @Inject
    ConfigurableApplicationContext context;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        JDBCCustomerDAO dao = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");

        dao.createTable();
        Customer c = new Customer();
        c.setAge(45);
        c.setName("ABC");
        c.setSurname("DEF");
        dao.insert(c);

        List<Customer> list = dao.findAll();
        for (Customer customer:list)
            System.out.println(customer);

    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        JDBCCustomerDAO dao = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");

        dao.dropTable();

    }
}

In order to read Spring’s XML configuration, we can deploy an @ApplicationScoped CDI Bean which produces Spring’s ClassPathXmlApplicationContext from the applicationContext.xml:

package com.sample;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@ApplicationScoped
public class SpringProducer {
    @Produces
    public ConfigurableApplicationContext create() {
        return new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    public void close(@Disposes final ConfigurableApplicationContext ctx) {
        ctx.close();
    }
}

Lastly, we will add a RowMapper for our Customer Class:

package com.sample;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

@SuppressWarnings("rawtypes")
public class CustomerRowMapper implements RowMapper	{
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        Customer customer = new Customer();
        customer.setSurname(rs.getString("SURNAME"));
        customer.setName(rs.getString("NAME"));
        customer.setAge(rs.getInt("AGE"));
        return customer;
    }
}

We are done with the code. Let’s add the applicationContext.xml file in the resources folder of your Maven project:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">

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

    <bean id="jdbcCustomerDAO" class="com.sample.JDBCCustomerDAOImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/ExampleDS"/>

    <bean id="txManager"
          class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManagerName" value="java:jboss/TransactionManager" />
        <property name="userTransactionName" value="java:jboss/UserTransaction" />
    </bean>

    <tx:annotation-driven transaction-manager="txManager" />
    <tx:jta-transaction-manager />

</beans>

Please notice we are using as TransactionManager the JBoss TransactionManager which is looked up via JNDI. Also, we lookup the DataSource “java:jboss/datasources/ExampleDS” from the application server.

When we deploy the application, provided that we have set to TRACE the “com.arjuna.ats.jta”, we can see the Transaction enlist and delist of the transactional resource:

2020-09-30 14:25:46,563 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,564 DEBUG [org.springframework.jdbc.core.JdbcTemplate] (ServerService Thread Pool -- 92) Executing prepared SQL update
2020-09-30 14:25:46,564 DEBUG [org.springframework.jdbc.core.JdbcTemplate] (ServerService Thread Pool -- 92) Executing prepared SQL statement [INSERT INTO CUSTOMER (NAME,SURNAME, AGE) VALUES (?, ?, ?)]
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.enlistResource ( LocalXAResourceImpl@45d3cf25[connectionListener=2f98cca3 connectionManager=74240d7a warned=false currentXid=null productName=H2 productVersion=@PROJECT_VERSION@ (2016-10-31) jndiName=java:jboss/datasources/ExampleDS] )
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.arjuna] (ServerService Thread Pool -- 92) StateManager::StateManager( 0:0:0:0:1 )
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.arjuna] (ServerService Thread Pool -- 92) AbstractRecord::AbstractRecord (0:0:0:0:1)
2020-09-30 14:25:46,564 TRACE [com.arjuna.ats.arjuna] (ServerService Thread Pool -- 92) LastResourceRecord()
2020-09-30 14:25:46,565 TRACE [com.arjuna.ats.arjuna] (ServerService Thread Pool -- 92) RecordList::insert(RecordList: empty) : appending /StateManager/AbstractRecord/LastResourceRecord for 0:0:0:0:1
2020-09-30 14:25:46,567 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,568 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,569 DEBUG [org.springframework.jdbc.core.JdbcTemplate] (ServerService Thread Pool -- 92) SQL update affected 1 rows
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) BaseTransaction.commit
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.commitAndDisassociate
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) SynchronizationImple.beforeCompletion - Class: class org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization HashCode: 1256027315 toString: org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@4add74b3
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) SynchronizationImple.beforeCompletion - Class: class org.wildfly.transaction.client.provider.jboss.JBossLocalTransactionProvider$1 HashCode: 706141901 toString: org.wildfly.transaction.client.provider.jboss.JBossLocalTransactionProvider$1@2a16decd
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) SynchronizationImple.beforeCompletion - Class: class org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization HashCode: 172725243 toString: org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@a4b93fb
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.equals
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
2020-09-30 14:25:46,569 TRACE [com.arjuna.ats.jta] (ServerService Thread Pool -- 92) TransactionImple.delistResource ( LocalXAResourceImpl@45d3cf25[connectionListener=2f98cca3 connectionManager=74240d7a warned=false currentXid=< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a057e34:-7a596d84:5f745755:27d, node_name=1, branch_uid=0:ffff0a057e34:-7a596d84:5f745755:281, subordinatenodename=null, eis_name=java:jboss/datasources/ExampleDS > productName=H2 productVersion=@PROJECT_VERSION@ (2016-10-31) jndiName=java:jboss/datasources/ExampleDS], 67108864 )

Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/spring/spring-demo-tx

Deploy your Spring Boot applications on OpenShift

[Updated!] Spring Boot is a new paradigm for developing Spring applications with more agility while focusing on your business methods rather than the thought of configuring Spring itself. In this tutorial we will learn how to deploy a Spring Boot application on Openshift Container Platform.

First of all, we will need a Spring Boot application to be deployed. We can use for this purpose the following application available on Github: https://github.com/fmarchioni/masterspringboot/tree/master/demo-docker

For more details on how this application has been created, please check How to deploy Spring Boot applications on Docker

Now start your Openshift Container Platform and login:

$ oc login 

We will create a project named myproject:

$ oc new-project myproject

Now in order to build our project we will use the redhat-openjdk-18 builder image which takes your application source or binary artifacts, builds the source using Maven, and assembles the artifacts with any required dependencies to create a new, ready-to-run image containing your Java application. This resulting image can be run on Openshift Container Platform Online or run directly with Docker.

Therefore, create a new application named “springboot-demo-docker”, which uses this image, available at the github repository we have mentioned at the beginning of this tutorial:

$ oc new-app registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift~https://github.com/fmarchioni/masterspringboot.git --context-dir=demo-docker --name=springboot-demo-docker

Please note that the context-dir has been used to create the application. This option allows us to build a project which is not in the root folder of your Git repository

Check your output, which will inform you that the Service is being created:

Found container image 74c8511 (13 days old) from registry.access.redhat.com for "registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift"

    Java Applications 
    ----------------- 
    Platform for building and running plain Java applications (fat-jar and flat classpath)

    Tags: builder, java

    * An image stream tag will be created as "openjdk18-openshift:latest" that will track the source image
    * A source build using source code from https://github.com/fmarchioni/masterspringboot.git will be created
      * The resulting image will be pushed to image stream tag "springboot-demo-docker:latest"
      * Every time "openjdk18-openshift:latest" changes a new build will be triggered
    * This image will be deployed in deployment config "springboot-demo-docker"
    * Ports 8080/tcp, 8443/tcp, 8778/tcp will be load balanced by service "springboot-demo-docker"
      * Other containers can access this service through the hostname "springboot-demo-docker"

-- Creating resources ...
    imagestream.image.openshift.io "openjdk18-openshift" created
    imagestream.image.openshift.io "springboot-demo-docker" created
    buildconfig.build.openshift.io "springboot-demo-docker" created
    deploymentconfig.apps.openshift.io "springboot-demo-docker" created
    service "springboot-demo-docker" created
-- Success
    Build scheduled, use 'oc logs -f bc/springboot-demo-docker' to track its progress.
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose svc/springboot-demo-docker' .

Let’s check that the service has been created:

$ oc get services
NAME                     CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
springboot-demo-docker   172.30.54.29   <none>        8080/TCP   16m

Last thing will be exposing our service externally:

$ oc expose svc/springboot-demo-docker
route "springboot-demo-docker" exposed

Here’s your nice pod running on the Openshift Container Platform web console:

You can click on it to check it’s working: nothing fancy but it does work:

Cool! We just deployed a sample Spring Boot application on Openshift Container Platform!

Another way to deploy Spring Boot applications (and generally speaking Java applications) on Openshift Container Platform is by using the OpenShift Maven plugin. You can check this tutorial for more details.

Do you want some more Spring stuff ? check Spring Boot Tutorials !

Spring Boot Hello World on WildFly

This article has been updated and tested with WildFly 20 and Spring Boot 2.3.3 release.

Spring Boot offers a new paradigm for developing Spring applications with more agility while focusing on your business methods rather than the thought of configuring Spring itself. Spring Boot does not require complex configuration files as it is able to discover classes by looking in the classpath of your applications and building a single runnable JAR of it, which makes it convenient to make your service portable too.

Creating a Spring Boot project

The simplest way to get started with Spring Boot is via the Spring Boot inizializer that is available on http://start.spring.io/

From there, choose the Spring Boot starters that you want to be included and artifactId and groupId. Also you can opt for a Maven project or a Gradle project.

As you can see, we have added only the “web” dependencies that will enable us to create a simple Web application with a REST endpoint.

Your first application

The Spring Boot Initilizer has created for us a sample application named SpringbootwildflyApplication. We will add some simple logic in it to map a GET request with a REST text resource. Copy in it the following text:

package com.mastertheboss.springboot.springbootwildfly;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@SpringBootApplication
public class SpringbootwildflyApplication   {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringbootwildflyApplication.class, args);
    }
}
 
 
@RestController
class HelloController {
 
    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
         
             return "Hi "+name+" !";
              
    }
}

Let’s see more in detail. The class is annotated with a @SpringBootAnnotation annotation. This is equivalent to applying the following Spring annotations:

  • @Configuration which identifies the class as a source of bean definitions for the application context.
  • @EnableAutoConfiguration which enables Spring Boot to add beans based on the application’s classpath, and various property settings.
  • @ComponentScan which tells Spring to look for other beans,configurations, and services in the same package as your application class so that you will be able to find the SimpleBean class.

Next, we have used the @RestController annotation to annotate a class that will encompass all of our REST APIs.  We will also use the @RequestMapping annotation to define the URL path to our API as well as HTTP method and path parameters for our APIs.

The is the pom.xml file used to build and package our first Project:

<?xml version="1.0" encoding="UTF-8"?>
<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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.mastertheboss.springboot</groupId>
	<artifactId>springbootwildfly</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>springbootwildfly</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>
</project>

As you can see, the list of dependencies is really minimal. You will find some extra repository configuration in case you are using a snapshot version of Spring Boot. All you have to do, in order to create the runnable JAR file is:

$ mvn clean package

You will generate a simple SpringBootBasic.jar file which can be run with:

$ java -jar target/springbootwildfly-0.0.1-SNAPSHOT.jar

The embedded Tomcat Web server will start, we can test that our application is working as follows:

Porting SpringBoot on a Java EE Container

Porting the Hello World application on a Java EE Container such as WildFly requires a few tweaks, mostly due to the fact that the application must be initialized and run by a Servlet container which is embedded into the application server. The first change will be extending the org.springframework.boot.web.servlet.support.SpringBootServletInitializer which is a WebApplicationInitializer to run a SpringApplication from a traditional WAR deployment:

package com.mastertheboss.springboot.springbootwildfly;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// Spring Boot 2.x
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

// Spring Boot 1.x
//import org.springframework.boot.web.support.SpringBootServletInitializer;
 
@SpringBootApplication
public class SpringbootwildflyApplication extends SpringBootServletInitializer {
 
    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }
 
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }
 
    private static Class<SpringbootwildflyApplication> applicationClass = SpringbootwildflyApplication.class;
}
 
@RestController
class HelloController {
 
    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
 
        return "Hi " + name + " !";
 
    }
}

Please note that we are using the org.springframework.boot.web.servlet.support.SpringBootServletInitializer and not the org.springframework.boot.web.support.SpringBootServletInitializer that has been deprecated in Spring Boot 2!

Next, some changes are also required in the pom.xml, in order to exclude the default Tomcat embedded Web server initializer and include the Servlet dependency in order to be able to compile the project:

<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>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.3.3.RELEASE</version>
      <relativePath />
      <!-- lookup parent from repository -->
   </parent>
   <groupId>com.mastertheboss.springboot</groupId>
   <artifactId>springbootwildfly</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>war</packaging>
   <name>springbootwildfly</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
         <exclusions>
            <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
         </exclusions>
      </dependency>
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
         <version>3.1.0</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <finalName>springbootwildfly</finalName>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
        <plugin>
           <groupId>org.wildfly.plugins</groupId>
           <artifactId>wildfly-maven-plugin</artifactId>
           <version>2.0.0.Final</version>
      </plugin>
      </plugins>
   </build>
   <repositories>
      <repository>
         <id>spring-snapshots</id>
         <name>Spring Snapshots</name>
         <url>https://repo.spring.io/snapshot</url>
         <snapshots>
            <enabled>true</enabled>
         </snapshots>
      </repository>
      <repository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>
   <pluginRepositories>
      <pluginRepository>
         <id>spring-snapshots</id>
         <name>Spring Snapshots</name>
         <url>https://repo.spring.io/snapshot</url>
         <snapshots>
            <enabled>true</enabled>
         </snapshots>
      </pluginRepository>
      <pluginRepository>
         <id>spring-milestones</id>
         <name>Spring Milestones</name>
         <url>https://repo.spring.io/milestone</url>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </pluginRepository>
   </pluginRepositories>
</project>

As we have included WildFly plugin into the configuration, in order to build and deploy the application on WildFly it is sufficient to run from the shell:

$ mvn clean package wildfly:deploy

You will notice from the application server logs that Spring Boot has been started and the Web application springbootwildfly.war has been deployed:

08:57:06,601 INFO  [stdout] (ServerService Thread Pool -- 88) 
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88)   .   ____          _            __ _ _
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88)  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88) ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88)  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88)   '  |____| .__|_| |_|_| |_\__, | / / / /
08:57:06,602 INFO  [stdout] (ServerService Thread Pool -- 88)  =========|_|==============|___/=/_/_/_/
08:57:06,604 INFO  [stdout] (ServerService Thread Pool -- 88)  :: Spring Boot ::        (v2.3.3.RELEASE)
08:57:06,604 INFO  [stdout] (ServerService Thread Pool -- 88) 
08:57:06,688 INFO  [com.mastertheboss.springboot.springbootwildfly.SpringbootwildflyApplication] (ServerService Thread Pool -- 88) Starting SpringbootwildflyApplication on fedora with PID 5909 (started by francesco in /home/francesco/jboss/wildfly-20.0.0.Final/bin)
08:57:06,690 INFO  [com.mastertheboss.springboot.springbootwildfly.SpringbootwildflyApplication] (ServerService Thread Pool -- 88) No active profile set, falling back to default profiles: default
08:57:07,282 INFO  [io.undertow.servlet] (ServerService Thread Pool -- 88) Initializing Spring embedded WebApplicationContext
08:57:07,282 INFO  [org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext] (ServerService Thread Pool -- 88) Root WebApplicationContext: initialization completed in 565 ms
08:57:07,637 INFO  [org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor] (ServerService Thread Pool -- 88) Initializing ExecutorService 'applicationTaskExecutor'
08:57:07,802 INFO  [com.mastertheboss.springboot.springbootwildfly.SpringbootwildflyApplication] (ServerService Thread Pool -- 88) Started SpringbootwildflyApplication in 1.471 seconds (JVM running for 48.732)
08:57:07,853 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (ServerService Thread Pool -- 88) Initializing Mojarra 2.3.9.SP10 for context '/springbootwildfly'
08:57:08,332 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 88) WFLYUT0021: Registered web context: '/springbootwildfly' for server 'default-server'
08:57:08,390 INFO  [org.jboss.as.server] (management-handler-thread - 1) WFLYSRV0010: Deployed "springbootwildfly.war" (runtime-name : "springbootwildfly.war")

We can test that our application is working as follows:

Troubleshooting

A frequent issue when building your Spring Boot to WildFly project is the following error:

java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig

 This can happen if you are using a Servlet API dependencies pre 3.x. Update your pom.xml with the 3.1.0 (or newer) javax.servlet-api !

Source code

You can check the source code for this article at: https://github.com/fmarchioni/mastertheboss/tree/master/spring/springbootwildfly

That’s all! In the next tutorial SpringBoot with JPA on WildFly we will learn how to use JPA with a Spring Boot application.

Do you want some more Spring stuff ? check Spring Boot Tutorials !

Your first JMS application with Spring Boot

This tutorial will teach you how to create a Spring Boot JMS application which sends messages to ArtemisMQ JMS Server. At the end of it, you will learn how to send messages from a generic Spring Boot application and from a Spring Boot REST Controller. Let’s get started!

In order to start, we will create a project which uses artemis dependencies. We can use Spring Boot CLI for this purpose and execute:

$ spring init -d=artemis artemis -x

Also, as we will be using ArtemisMQ in embedded mode, we will also need to add the dependency “artemis-jms-server” to bootstrap the server:

<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>artemis-jms-server</artifactId>
</dependency>

Here is the final pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.mastertheboss.springboot</groupId>
	<artifactId>SpringBootJMS</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-artemis</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>artemis-jms-server</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

We need to configure one Queue that will be used for sending and receiving messages. We can do this into the application.properties file:

spring.artemis.mode=embedded
spring.artemis.embedded.enabled=true
spring.artemis.embedded.queues=springbootQueue
myqueue=springbootQueue

Within the configuration, we have declared the server to run in embedded mode, along with the Queue name to be “springbootQueue“. Now let’s look at the producer that will our main DemoApplication class:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;

@SpringBootApplication
public class DemoApplication {
	private static final Logger log = LoggerFactory.getLogger(DemoApplication.class);

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Value("${myqueue}")
	String queue;

	@Bean
	CommandLineRunner start(JmsTemplate template) {
		return args -> {
			log.info("Sending> ...");

			template.convertAndSend(queue, "Hello World from Spring Boot!");
		};
	}
}

As we want to test message from the main application, we have defined a @Bean CommandLineRunner method. This method will therefore be executed after the Spring Boot finishes its pre-configuration. Also, this method uses the JmsTemplate instance, which will be autowired in the method automatically. The JmsTemplate uses the convenience convertAndSend method to send an Hello World message. To consume messages, we will be adding a Message Consumer Class:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Consumer implements MessageListener{
	private Logger log = LoggerFactory.getLogger(Consumer.class);
	@Override
	public void onMessage(Message message) {
		try {
			log.info("Received message: " + message.getBody(Object.class));
		}catch (JMSException ex) {
			ex.printStackTrace();
		}
	}
}

Within this class, we have:

  • Implemented a MessageListener
  • Implemented the onMessage method to receive messages asynchronously.

Finally, we need to do plug into our project some extra configuration to connect to the ArtemisMQ server:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.listener.DefaultMessageListenerContainer;

import javax.jms.ConnectionFactory;

@Configuration
public class MessagingConfig {
	@Autowired
	private ConnectionFactory connectionFactory;
	@Value("${myqueue}")
	private String queue;

	@Bean
	public DefaultMessageListenerContainer messageListener() {
		DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
		container.setConnectionFactory(this.connectionFactory);
		container.setDestinationName(queue);
		container.setMessageListener(new Consumer());
		return container;
	}
}

The @Configuration annotation tells Spring to configure any declared methods annotated with the @Bean annotations.

  • We have @Autowired a ConnectionFactory for creating a connection with the default user identity to the broker. In this case it will create the connection to the ArtemisMQ server with the default credentials.
  • Finally, the @Bean messageListener defines a bean that will return a DefaultMessageListenerContainer instance. The DefaultMessageListenerContainer will be responsible for connecting to the queue and listening through the consumer’s MessageListener interface implementation.

That’s all. You can run the application with:

$ ./mvnw spring-boot:run

After running the program you should have the logs from the consumer and producer, something similar to this:

INFO 27897 --- [           main] com.example.artemis.DemoApplication      : Started DemoApplication in 2.624 seconds (JVM running for 3.183)
INFO 27897 --- [           main] com.example.artemis.DemoApplication      : Sending> ...
INFO 27897 --- [ssageListener-1] com.example.artemis.Consumer             : Received message: Hello World from Spring Boot!

Adding a Controller to send messages

We can make our example more dynamic by adding a REST Controller that will send a message received as PathVariable along with the request:

@RestController
public class RESTController {

    @Autowired private JmsTemplate jmsTemplate;

    @RequestMapping("/send/{message}")
    public String sendMessage(@PathVariable String message) {
        try {
            jmsTemplate.convertAndSend("springbootQueue",message);
            return "message sent!";
        } catch (Exception e) {
            e.printStackTrace();
            return "Error in sending message!";
        }


    }
}

That will require an extra dependency to run:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

You can now test the application, passing the message in the path. Example:

curl http://localhost:8080/send/john

Resulting in the log:

2019-12-19 19:03:02.696  INFO 18210 --- [ssageListener-1] c.m.springboot.SpringBootJMS.Consumer    : Received message: john

Sending Objects in the Message Payload

Provided that your objects are Serializable, they can be sent as payload in your JMS Messages. So assumed that you have the following Java POJO Class:

import java.io.Serializable;

public class Customer implements Serializable{
    String name;
    String surname;

    public Customer() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", surname='" + surname + '\'' +
                '}';
    }
}

Now you can add a method to our Controller, which sends the Customer. The Customer needs to be sent in JSON format:

    @RequestMapping(path="/sendCustomer", method = RequestMethod.POST, consumes = {"application/json"})
    public void sendCustomer(@RequestBody Customer customer) {
        System.out.println("Sending customer "+customer);
        jmsTemplate.convertAndSend("springbootQueue", customer);
    }

For example, you can send it as follows:

curl -d '{"name":"john", "surname":"smith"}' -H "Content-Type: application/json" -X POST http://localhost:8080/sendCustomer

Resulting in the following log:

2019-12-19 19:00:17.798 INFO 17662 --- [ssageListener-1] c.m.springboot.SpringBootJMS.Consumer : Received message: Customer{name='john', surname='smith'}

Adding Connectors to the Embedded ArtemisMQ Server

In our example, Spring Boot Artemis starter creates a Configuration bean which will be used for EmbeddedJMS configuration. The Embedded JMS Server will only use an InVMAcceptorFactory, therefore it will not be available to remote clients. If you want to add extra Connectors configurations, you can implement the ArtemisConfigurationCustomizer interface and override the customize method, as in this example:

import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MessagingConfig implements ArtemisConfigurationCustomizer {
    @Override
    public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
        configuration.addConnectorConfiguration("nettyConnector", new TransportConfiguration(NettyConnectorFactory.class.getName()));
        configuration.addAcceptorConfiguration(new TransportConfiguration(NettyAcceptorFactory.class.getName()));
    }
}

Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/spring/SpringBootJMS

Do you want some more Spring Boot stuff ? check Spring Boot Tutorials !

Configuring the DataBase in Spring Boot applications

In this tutorial we have learn how to setup a Spring Boot JPA application and deploy in on a Java EE container using the default H2 database: SpringBoot with JPA on WildFly. Now we will learn how to change the Database settings.

So here’s the initial Project https://github.com/fmarchioni/mastertheboss/tree/master/spring/SpringBootJPA we have built so far:

SpringBootJPA/
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── mastertheboss
        │           └── springboot
        │               ├── App.java
        │               ├── model
        │               │   └── City.java
        │               └── service
        │                   ├── CityRepository.java
        │                   ├── CityServiceImpl.java
        │                   └── CityService.java
        ├── resources
        │   ├── application.properties
        │   ├── import.sql
        │   ├── log4jdbc.log4j2.properties
        └── webapp

What we need is at first specifying the JDBC settings in the file application.properties. Supposing we will use PostgreSQL:

spring.datasource.url=jdbc:postgresql://localhost/demodb
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto = create-drop

Of course the property spring.jpa.hibernate.ddl-auto = create-drop is set just for demonstration purposes! Next, don’t forget to include the JDBC driver dependency in your pom.xml file:

<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.1-901-1.jdbc4</version>
</dependency>

Finally, some adjusting might be required to handle the auto-generation of the primary key.

package com.mastertheboss.springboot.model;

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class City implements Serializable {

	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Basic(optional = false)
	@NotNull
	@Column(name = "id", nullable = false)
	private Integer id;

	@Column(nullable = false)
	private String name;

	@Column(nullable = false)
	private String state;

	@Column(nullable = false)
	private String country;

	@Column(nullable = false)
	private String map;

	protected City() {
	}

	public City(String name, String country) {
		super();
		this.name = name;
		this.country = country;
	}

	public String getName() {
		return this.name;
	}

	public String getState() {
		return this.state;
	}

	public String getCountry() {
		return this.country;
	}

	public String getMap() {
		return this.map;
	}

	@Override
	public String toString() {
		return getName() + "," + getState() + "," + getCountry();
	}
}

We have used the @GeneratedValue annotation to specify how the primary key should be generated. In our case, we are using an Identity strategy which indicates that the database (Postgresql) must assign primary keys for the entity using a database identity column.

That’s all. Build, Deploy, Test it!

Do you want some more Spring stuff ? check Spring Boot Tutorials !

Spring Boot with JPA on WildFly

In this second tutorial about Spring Boot we will learn how to deploy a JPA based application on a Java EE container such as WildFly 10.

We recommend going through our first tutorial to learn how to setup quickly a Maven project with Spring Boot: Spring Boot Hello World on WildFly

So we assumed you have created a basic Maven project: start adding the main class App.java which contains also the RestController to interact with our CityService:

package com.mastertheboss.springboot;

import java.util.List;

import com.mastertheboss.springboot.model.City;
import com.mastertheboss.springboot.service.CityService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class App extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(applicationClass, args);
	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(applicationClass);
	}

	private static Class<App> applicationClass = App.class;
}

@RestController
@RequestMapping("/rest")
class HelloController {

	@Autowired
	private CityService cityService;

	@RequestMapping("/find/{city}/{country}")
	String find(@PathVariable String city, @PathVariable String country) {

		return cityService.getCity(city, country).toString();

	}

	@RequestMapping(value = "/findAll", headers = "Accept=application/json")
	List<City> findAll() {

		List<City> list = cityService.findAll();
		return list;

	}

}

So the HelloController maps two REST GET methods: find and findAll. The first one will return the result of a query using city and country as parameter. The second will return all the City objects available.

In Spring Service classes are the equivalent, in JEE terms, of EJBs as they can be used to hold business logic and calculations. Following here is the simple implementation of the CityService interface which adds some trivial logic to it, such as validating parameters.

package com.mastertheboss.springboot.service;


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.mastertheboss.springboot.model.City;

@Component("cityService")
@Transactional
class CityServiceImpl implements CityService {

	@Autowired
	private CityRepository cityRepository;


	public CityServiceImpl( ) {	}
	 
	@Override
	public City getCity(String name, String country) {
		Assert.notNull(name, "Name must not be null");
		Assert.notNull(country, "Country must not be null");
		return this.cityRepository.findByNameAndCountryAllIgnoringCase(name, country);
	}

	@Override
	public List<City> findAll() {
		 
		return this.cityRepository.findAll();
	}

 }

This class is annotated with @Component which is generic stereotype for any Spring-managed component. By using @Transactional, many important aspects such as transaction propagation are handled automatically by Spring. And here’s its interface definition:

package com.mastertheboss.springboot.service;

import java.util.List;

import com.mastertheboss.springboot.model.City;

public interface CityService {

    City getCity(String name, String country);
    List<City> findAll();	 

}

Last part of the project are the Repository classes which are the beans eligible for handling persistence. This interface acts primarily as a marker interface to capture the types to work with and providing sophisticated CRUD functionality for the entity class that is being managed. In our case, the findAll method will return all domain objects of type City and findByNameAndCountryAllIgnoringCase is equivalent to a case-insensitive “SELECT * from City where name = ? and country = ?

package com.mastertheboss.springboot.service;

import java.util.List;
import org.springframework.data.repository.Repository;

import com.mastertheboss.springboot.model.City;

interface CityRepository extends Repository<City, Long> {

	City findByNameAndCountryAllIgnoringCase(String name, String country);
	List<City> findAll();

}

Finally, the Domain class which is annotated with JPA javax.persistence classes:

package com.mastertheboss.springboot.model;

import java.io.Serializable;

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

@Entity
public class City implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue
	private Long id;

	@Column(nullable = false)
	private String name;

	@Column(nullable = false)
	private String state;

	@Column(nullable = false)
	private String country;

	@Column(nullable = false)
	private String map;

	protected City() {
	}

	public City(String name, String country) {
		super();
		this.name = name;
		this.country = country;
	}

	public String getName() {
		return this.name;
	}

	public String getState() {
		return this.state;
	}

	public String getCountry() {
		return this.country;
	}

	public String getMap() {
		return this.map;
	}

	@Override
	public String toString() {
		return getName() + "," + getState() + "," + getCountry();
	}
}

That’s all. In order to produce a war file, we need to specify the correct packaging in the pom.xml and also exclude the default Tomcat Starter classes. In this simple example we have used the default H2 database to persist our objects:

<?xml version="1.0" encoding="UTF-8"?>
<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.mastertheboss.springboot</groupId>
	<artifactId>SpringBootJPA</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>Spring Boot Demo Project with JPA</name>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.0.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>

			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>

		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>

	</dependencies>
	<properties>
		<java.version>1.8</java.version>
	</properties>


	<build>
		<finalName>SpringBootJPA</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

In order to add some default data at application deployment, you could include a file import.sql under the resources folder of your project:

insert into city(country, name, state, map) values ('Italy', 'Roma', 'Lazio', '-27.470933, 153.023502') 
insert into city(country, name, state, map) values ('France', 'Paris', 'IleDeFrance', '-37.813187, 144.96298')

Now compile as usual the project with:

$ mvn clean package

You will generate a SpringBootJPA.war file which can be deployed with:

$ cp target/SpringBootJPA.war %JBOSS_HOME/standalone/deployments

We can test that our application is working as follows:

$ wget http://localhost:8080/SpringBootJPA/rest/findAll
$ wget http://localhost:8080/SpringBootJPA/rest/findByNameAndCountryAllIgnoringCase/Roma/Italy

You can download the full project on Github at: https://github.com/fmarchioni/mastertheboss/tree/master/spring/SpringBootJPA

In the following tutorial (Configuring the DataBase in Spring Boot applications) we will learn how to change the default H2 database to use PostgreSQL.

Do you want some more Spring stuff ? check Spring Boot Tutorials !

Using Spring Retry to consume REST Services

Spring-retry is one of the many side-projects of Spring: the famous dependency injection framework. This library let us automatically re-invoke a method, moreover this operation it’s trasparent to the rest of our application. In this post I will try to illustrate the main features of this API, using a simple example.

Setup

To add Spring-retry to your project, you just need to add the following dependencies to your pom.xml file:

<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
</dependency>

Spring Retry Use case

Our purpose is to obtain the current Euro/Dollar exchange rate consuming a REST service. If the server responds with a HTTP code 503, we will relaunch the method unitil the server responds with a 200 code. Here is the service implementation:

@Path("/fetchRate")
public class ChangeService {

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public Response getChange(@QueryParam("from") String from,
			@QueryParam("to") String to) {
		Random randomGenerator = new Random();
		int randomInt = randomGenerator.nextInt(2);

		if (from.equals("EUR") && to.equals("USD")) {
			if (randomInt == 1)
				return Response.status(200).entity("1.10").build();
			else
				return Response.status(503)
						.entity("Service temporarily not available").build();
		} 
		return Response.status(500).entity("Currency not available").build();

	}

}

 As you can see, in order to simulate a service which is temporarily unavailable we are using a Random generator which returns a 503 error on 50% of the invocations.

@Retryable

The “heart” of spring-retry is the @Retryable annotation. With the maxAttempts attribute we will set how many times the method should be invoked. With the @Backoff annotation we will configure an initial delay in milliseconds; this delay will increase of a 50% factor for every iteration. Let’s have a look at the full code of the REST client to understand how this annotation works.

public class RealExchangeRateCalculator implements ExchangeRateCalculator {
	
	private static final double BASE_EXCHANGE_RATE = 1.09;
	private int attempts = 0;
	private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
	
	@Retryable(maxAttempts=10,value=RuntimeException.class,backoff = @Backoff(delay = 10000,multiplier=2))
	public Double getCurrentRate() {
		
		System.out.println("Calculating - Attempt " + attempts + " at " + sdf.format(new Date()));
		attempts++;
		
		try {
			HttpResponse<JsonNode> response = Unirest.get("http://rate-exchange.herokuapp.com/fetchRate")
				.queryString("from", "EUR")
				.queryString("to","USD")
				.asJson();
			
			switch (response.getStatus()) {
			case 200:
				return response.getBody().getObject().getDouble("Rate");
			case 503:
				throw new RuntimeException("Server Response: " + response.getStatus());
			default:
				throw new IllegalStateException("Server not ready");
			}
		} catch (UnirestException e) {
			throw new RuntimeException(e);
		}
	}
	
	@Recover
	public Double recover(RuntimeException e){
		System.out.println("Recovering - returning safe value");
		return BASE_EXCHANGE_RATE;
	}

}

In case of a RuntimeException, the getCurrentRate method will be automatically reinvoked 10 times. If during the last execution the method fails again, the method annotated with @Recover will be launched. If there’s no recover method, the exception it’s simply throwed up.

XML Configuration

All of our configuration are made via annotations. Spring-retry, just like its greater brother Spring Framework can use the XML configuration. In this case we use the aspect-oriented programming, adding an Interceptor to our beans with this configuration:

<aop:config>
    <aop:pointcut id="retryable" expression="execution(* it..*RateCalculator.getCurrentRate(..))" />
    <aop:advisor pointcut-ref="retryable" advice-ref="retryAdvice" order="-1"/>
</aop:config>

<bean id="retryAdvice" class="org.springframework.batch.retry.interceptor.RetryOperationsInterceptor"/>

The source code for this Spring application is available on Github.

Using Spring Retry with Spring Boot

Let’s see now an example about String retry using Spring Boot framework. The logic does not change comparing to the standard Spring application. We will code a Controller class which uses a Database to retrieve a list of Customer objects. Should this fail, a static list of Customer objects will be returned:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
public class CustomerController {
    @Autowired
    CustomerRepository repository;
    List<Customer> customerList = new ArrayList<Customer>();

    @PostConstruct
    public void init() {
        customerList.add(new Customer(1, "frank"));
        customerList.add(new Customer(2, "john"));
    }

    @RequestMapping("/list")
    @Retryable(value = {ServiceNotAvailableException.class}, maxAttempts = 2, backoff = @Backoff(delay = 1000))
    public List<Customer> findAll() {

        int random = new Random().nextInt(2);

        if (random == 1) {
            throw new ServiceNotAvailableException("DB Not available! using Spring-retry..");
        }
        System.out.println("Returning data from DB");
        return repository.findAll();
    }

    @Recover
    public List<Customer> getBackendResponseFallback(ServiceNotAvailableException e) {
        System.out.println("Returning cached list.");
        return customerList;
    }

}

As you can see, the logic is contained in the findAll method which uses a Random generator to simulate a failure in accessing the Database. This is allowed up to 2 attempts. If that fails more than maxAttempts, the @Recover method will be triggered, to return the customerList from an ArrayList.
We need to add @EnableRetry on the top of our SpringBoot application:

@SpringBootApplication
@EnableRetry
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

Upon start, the application will insert some data in the H2 Database, so that the findAll method is able to return a set of records:

INSERT into CUSTOMER (id,name) VALUES (10, 'frank');
INSERT into CUSTOMER (id,name) VALUES (20, 'john');

To connect to the H2 Database, we will include the following configuration in the resources/application.properties file:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

The full source code for the application is available on GitHub: https://github.com/fmarchioni/mastertheboss/tree/master/spring/demo-retry

Do you want some more Spring Boot stuff ? check Spring Boot Tutorials !

Spring JDBC application on WildFly

This tutorial demonstrates how to develop a Web application using PrimeFaces for the User Interfaces, Spring JDBC for handling persistence and CDI as glue between these technologies.

Although there are many technologies in this tutorial, you will see that mixing them is not complicated at all. You need a basic Web project as startup; for example the webapp-javaee7 can fit this purpose:

$ mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes \
-DarchetypeArtifactId=webapp-javaee7 \
-DarchetypeRepository=https://nexus.codehaus.org/content/repositories/snapshots \
-DgroupId=mastertheboss \
-DartifactId=springjdbc \
-Dversion=1.0 \
-Dpackage=mastertheboss \
-Darchetype.interactive=false --batch-mode --update-snapshots archetype:generate

The first class that we will add is a CDI Bean which is in charge to produce and dispose the ConfigurableApplicationContext:

@ApplicationScoped
public class SpringProducer {
     @Produces
        public ConfigurableApplicationContext create() {
            return new ClassPathXmlApplicationContext("applicationContext.xml");
        }

        public void close(@Disposes final ConfigurableApplicationContext ctx) {
            ctx.close();
        }
}

The  ConfigurableApplicationContext is a provider interface which is used to provide an application context to Spring application, by loading beans definition into the file applicationContext.xml

Here is the applicationContext.xml file which defines a Spring Bean named jdbcCustomerDAO and a datasource that is retrieved from the JNDI at “java:jboss/datasources/ExampleDS” (This is the default H2 database included in JBoss/WildFly distribution):

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/aop 

http://www.springframework.org/schema/aop/spring-aop-3.2.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/jeehttp://www.springframework.org/schema/jee/spring-jee-3.2.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.2.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.2.xsd">
    
    <bean id="jdbcCustomerDAO" class="mastertheboss.dao.JDBCCustomerDAOImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/ExampleDS"/>
 
</beans>

Let’s see the definition of the class JDBCCustomerDAOImpl:

public class JDBCCustomerDAOImpl implements JDBCCustomerDAO {
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void createTable() {
        jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate
                .execute("create table customer (name varchar, surname varchar, age integer)");
    }

    public void dropTable() {
        jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.execute("drop table customer");
    }

    public void insert(Customer customer) {

        String sql = "INSERT INTO CUSTOMER "
                + "(NAME,SURNAME, AGE) VALUES (?, ?, ?)";

        jdbcTemplate = new JdbcTemplate(dataSource);

        jdbcTemplate.update(sql,
                new Object[] { customer.getName(), customer.getSurname(),
                        customer.getAge() });
    }

    @SuppressWarnings("rawtypes")
    public List<Customer> findAll() {

        jdbcTemplate = new JdbcTemplate(dataSource);
        String sql = "SELECT * FROM CUSTOMER";

        List<Customer> customers = new ArrayList<Customer>();

        List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
        for (Map row : rows) {
            Customer customer = new Customer();
            customer.setSurname((String) row.get("SURNAME"));
            customer.setName((String) row.get("NAME"));
            customer.setAge(Integer.parseInt(String.valueOf(row.get("AGE"))));
            customers.add(customer);
        }

        return customers;
    }

}

As you can see, this class uses Spring JDBC template API for handling database persistence, which is an alternative to plain JDBC (where you have to code by yourself all the JDBC creation/disposal layer) and to JPA/Hibernate where Database table and fields are represented as Java types.

When using Spring JDBCTemplate, the mapping is handled by implementing the RowMapper interface and the mapRow method, which receives as input the single record as a ResultSet and returns a generic Object type:

public class CustomerRowMapper implements RowMapper    {
        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Customer customer = new Customer();
            customer.setSurname(rs.getString("SURNAME"));
            customer.setName(rs.getString("NAME"));
            customer.setAge(rs.getInt("AGE"));
            return customer;
        }
}

The Customer class which is referenced, contains the fields that are arriving from the UI and uses the DAO class for inserting and retrieving the list of Customers:

@Model
public class Customer {
    @Inject
    ConfigurableApplicationContext context;
    
    private String name;
    private String surname;
    private int age;

    public Customer() { }

    public Customer(String name, String surname, int age) {
        this.name = name;
        this.surname = surname;
        this.age = age;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void insertCustomer() {
        JDBCCustomerDAO dao = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");
        Customer emplNew = new Customer(name, surname, age);
        dao.insert(emplNew);

    }

    List<Customer> customerList;

    public void setCustomerList(List<Customer> customerList) {
        this.customerList = customerList;
    }

    public List<Customer> getCustomerList() {
        JDBCCustomerDAO jdbcEmployeeDAO = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");

        this.customerList = jdbcEmployeeDAO.findAll();
        return customerList;
    }
}

That’s all! easy-peasy! The last class I’ve included is a ContextListener that is used for creating and dropping the table used after each deployment (I do accept suggestions and tips to improve this approach):

@WebListener
public class MyContextListener implements ServletContextListener {
    @Inject
    ConfigurableApplicationContext context;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        JDBCCustomerDAO dao = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");

        dao.createTable();

    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        JDBCCustomerDAO dao = (JDBCCustomerDAO) context
                .getBean("jdbcCustomerDAO");

        dao.dropTable();

    }
}

This application has a Primefaces front-end that contains an upper panel for inserting a Customer and a tabular list of data in the lower panel:

<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">
<h:head></h:head>

<h:body>

    <h:form id="jsfexample">
        <p:panelGrid columns="2">
            <f:facet name="header">Enter Customer</f:facet>
            <h:outputText value="Name" />
            <h:inputText value="#{customer.name}" />

            <h:outputText value="Surname" />
            <h:inputText value="#{customer.surname}" />

            <h:outputText value="Age" />
            <h:inputText value="#{customer.age}" />
            <f:facet name="footer">
                <h:commandButton actionListener="#{customer.insertCustomer}"
                    styleClass="buttons" value="Insert Customer" />

            </f:facet>
        </p:panelGrid>
    </h:form>
    <br />
    <h:outputText value="Customer List" />
    <br />
    <p:dataTable var="c" value="#{customer.customerList}">


        <p:column headerText="Name">
            <h:outputText value="#{c.name}" />
        </p:column>

        <p:column headerText="Surname">
            <h:outputText value="#{c.surname}" />
        </p:column>
        <p:column headerText="Age">
            <h:outputText value="#{c.age}" />
        </p:column>

    </p:dataTable>

</h:body>
</html>

Here is how the application looks like when running:

That’s all. You can download the Maven project from here. In the next tutorial we will show how to install Spring as a module on WildFly. Stay tuned!

Do you want some more Spring stuff ? check Spring Boot Tutorials !