Category Archives: Maven

Define Restful web services using Spring

In one of my project, I had the difficult decision to switch to another technology: I replaced JSF with Angular-JS.
Our goal was to speed up the development by removing the painful part implied with JSF, as a lot of server requests to manage, some view state issues, the refresh management, the need to implement the view on the Java part with its managed beans, etc…

But the big impact on the architectural point of view was that we have to move the GUI (and its logic) on the client side and give access to the data. Fortunately, this part was ease by the layered structure of the application, I just need to replace the old JSF part with a REST interface which is accessed by the Angular-JS components using Ajax requests.
As the project used already Spring, I decided to use it also to set up the restful part, I describe hereafter what I did.

First of all, we need to add the corresponding dependencies in our POM:

<properties>
    <spring.framework.version>4.0.5.RELEASE</spring.framework.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
            <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.12</version>
    </dependency>
</dependencies>

We need also to activate the configuration using annotation, for that we have to add in our Spring configuration file:

    <context:component-scan base-package="net.classnotfound.ws"/>
    <mvc:annotation-driven />

Even if I do not like to use the annotations to configure the application, I decided to make an exception for the web services, as they are not intended to have some intelligence and are just a bridge to the business layer, I consider it as acceptable.

A web service is declared using the @RestController Spring annotation:

package net.classnotfound.ws.controller;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
	//Web service implementation here
    
}

When we define an endpoint for the web service, we need to indicates which HTTP method we use, the type of data we expect (JSON is the usual case), etc…
This can be done easily by using the Spring annotation:

    @RequestMapping(value = "/service/print", method = RequestMethod.POST, consumes = {"application/json" })
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void print(@RequestBody final Data data) {
        System.out.println(data);
    }

Here, we defined a method print, which is reachable using “/service/print” URL, using a POST request with data in JSON format.
The @ResponseStatus is used to define the HTTP return code to be used.

Another option is to use a GET method, but doing this, the parameters are now directly provided with the requested URL:

    @Autowired
    private DataService dataService;

    @Transactional
    @Globals
    @RequestMapping(value = "/service/data/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Data find(@PathVariable("id") final String id) {
        Data data = dataService.find(id);
        if (data==null) {
            throw new ObjectNotFoundException(id);
        }
        return data;
    }

We can see the parameter defined in the URL using a EL syntax and this parameter is also mentioned in the signature of the method using @PathVariable annotation.

Too easy, isn’t it? 😀

Spring MyBatis configuration

Here I describe the project configuration to use MyBatis as ORM and benefit of the transactions management provided by Spring.
For that, we have to add the MyBatis-Spring library to the basic MyBatis.

First, the Maven POM is like:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.3</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.1</version>
</dependency>

And now, the Spring configuration file where we define the SqlSessionFactoryBean:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath:xml/*Mapper.xml" />
    </bean>
</beans>

The SqlSessionFactoryBean needs a datasource, and also the location of the MyBatis xml mappers.

Now, the configuration is done and the mappers will be managed by Spring using with this:

<!-- this is the parent of our Mappers. It defines the sqlSessionFactory which is common to all our mapper beans -->
<bean id="mapper" abstract="true">
	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- Place MyBatis Mappers here -->
<bean id="entityMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" parent="mapper">
	<property name="mapperInterface"
		value="net.classnotfound.data.mapper.EntityMapper" />
</bean>

We can see that the mappers are instantiated by the org.mybatis.spring.mapper.MapperFactoryBean which needs a reference to the SqlSessionFactory object we defined earlier.
To avoid some oversights (and reduce the mount of lines I have to write :) ), I use the “abstract” Spring feature to put the session factory in the abstract mapper, then I can reference it as a parent in all my MapperFactories.

Now the entityMapper we defined is “injectable” in our Spring managed beans and we can use our preferred way of transaction management.

Display Maven release number in JSF page

In the web projects, it is often useful to see quickly the version of the deployed application. A simple solution is to get it from Maven and display it in our page, in footer or a “about” page.
The main idea is to use a property file as a JSF resource as we can use, for example, when we have a i18n requirement.
For that, I put a property file version.properties with content in the resource directory:

version=${version}
revision=${buildNumber}

The version is the version defined in our project pom and it is automatically provided by Maven.
The revision is the revision number of the last build provided by SVN, to get it, I will need another Maven plugins.

Now, I need to tell to JSF to use this file as resource file, I do it in my faces-config.xml:

<application>
	<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
	<resource-bundle>
	   <base-name>version</base-name>
	   <var>vers</var>
	</resource-bundle>
</application>

And to display it in our JSF pages, I add:

<body>
   [...]
	<div>classNotFound.net ©2014 -
		v#{vers.version} - #{vers.revision}</div>
</body>

If I try to access to this page, I will not see the version/revision, to do that, I have to ask Maven to filter the properties files and replace the variables.
In my pom.xml, I add:

<build>
	<resources>
		<resource>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
			<includes>
				<include>**/*</include>
			</includes>
		</resource>
	</resources>
</build>

To have the build number, I have to use 3 Maven plugins:

<pluginManagement>
        <plugins>
            <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>buildnumber-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>validate</phase>
                    <goals>
                        <goal>create</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <doCheck>false</doCheck>
                <doUpdate>false</doUpdate>
                <providerImplementations>
                    <svn>javasvn</svn>
                </providerImplementations>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>com.google.code.maven-scm-provider-svnjava</groupId>
                    <artifactId>maven-scm-provider-svnjava</artifactId>
                    <version>2.0.2</version>
                </dependency>
                <dependency>
                    <groupId>org.tmatesoft.svnkit</groupId>
                    <artifactId>svnkit</artifactId>
                    <version>1.7.5-v1</version>
                </dependency>
            </dependencies>
        </plugin>
        </plugins>
    </pluginManagement>
  </build>
  
    <scm>
        <connection>scm:svn:https://forge.classnotfound.net/svn/version/trunk/project/project-web</connection>
        <developerConnection>scm:svn:https://forge.classnotfound.net/svn/project/trunk/project/project-web</developerConnection>
        <url>https://forge.classnotfound.net/svn/project/trunk/project/project-web</url>
    </scm>

Now, it works.

Change web context using Maven

<packaging>war</packaging>
<build>
<plugins>
  <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
    <configuration>
        <packagingExcludes>WEB-INF/web.xml</packagingExcludes>
        <warName>exp-elec-web</warName>
    </configuration>
</plugin>
</plugins>
</build>

Maven config for JSF2/RichFaces

Here is my Maven configuration for a JSF2/Richfaces 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>

    <groupId>net.classnotfound</groupId>
    <artifactId>jsf</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>jsf</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <org.apache.myfaces.version>2.2.0</org.apache.myfaces.version>
        <org.richfaces.version>4.3.5.Final</org.richfaces.version>
    </properties>

    <dependencies>

        <!-- web container dependencies -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper</artifactId>
            <version>7.0.50</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSF dependencies -->
        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-bundle</artifactId>
            <version>${org.apache.myfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-digester</groupId>
            <artifactId>commons-digester</artifactId>
            <version>2.1</version>
        </dependency>
        <!-- end JSF dependencies -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- RichFaces dependencies -->
        <dependency>
            <groupId>org.richfaces.core</groupId>
            <artifactId>richfaces-core-api</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.core</groupId>
            <artifactId>richfaces-core-impl</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.ui.common</groupId>
            <artifactId>richfaces-ui-common-api</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.ui.core</groupId>
            <artifactId>richfaces-ui-core-api</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.ui</groupId>
            <artifactId>richfaces-components-api</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.ui</groupId>
            <artifactId>richfaces-components-ui</artifactId>
            <version>${org.richfaces.version}</version>
        </dependency>
        <dependency>
            <groupId>org.w3c.css</groupId>
            <artifactId>sac</artifactId>
            <version>1.3</version>
        </dependency>
        <!-- End RichFaces dependencies -->
    </dependencies>
</project>

Define the Java version in Maven

Directly in the pom.xml (resource definition is also included):

<?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">
...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*</include>
            </includes>
            <excludes>
                <exclude>profiles/**</exclude>
            </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/profiles/${profile.name}</directory>
                <includes>
                    <include>*.properties</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>