IntelliJ reports that there is more than one bean of a repository, although app starts up fine

I’ve come across an issue recently in a project where I was using Spring Data JPA. I had a repository defined like this:

@Repository
public interface QuestionCategoryRepository extends JpaRepository<QuestionCategory, Long> {

}

I also had a service class where I injected this repository:

@Inject
private QuestionCategoryRepository questionCategoryRepository;

I noticed, that IntelliJ reported the following error: “There is more than one bean of QuestionCategoryRepository type”. It seemed wierd to me, so I went ahead and started my application. The context was built successfully and there were no problems with the startup at all.

It turned out that IntelliJ really had provided me a useful hint, because I noticed that I have an

@ComponentScan(basePackages = "...")

annotation on my class that is used for persistence related configuration. The scope of this annotation was involving the package where I had my repositories defined.

This is why IntelliJ believed, that there are two definitions.

Actually, there were three.

I also noticed that I have

@EnableJpaRepositories(basePackages = "...")

on my configuration class, pointing to the packes where my repositories reside.

It turned out that I can remove both the @Repository annotation and the @ComponentScan as well, becauses the @EnableJpaRepositories was enough to detect my repositories. Of course, @ComponentScan might need to be kept if it is for scanning some other classes.

Keep form field values and errors after redirection in Spring MVC controller

Ways for processing form submit

When you are processing a form submit using Spring MVC, if there are validation errors, you can:

  1. Return the errors in the response to the form submit request (POST request usually).
  2. Redirect the user to the form and return the result from this new request.

The first option has a drawback that if the user refreshes the page after we return with the response, the form will be resubmitted the same way as before (also he’ll see the confirmation popup asking if it is okay to do that). On one hand, most of the users won’t even understand the situation, on the other hand if the user decides to resubmit the form, sometimes unwanted situations might happen.

Also, another case to consider, if the user just wants to refresh the page to get an empty form, he’ll not succeed because he’ll still see the errors and filled values from the previous submission.

Because of these reasons the second option might be preferred, let’s see how to do that

Retaining filled values and errors upon redirect

First let’s see the whole code of a controller that implements the solution:

package com.devsphinx.web.controller.user;

import com.devsphinx.web.controller.BaseController;
import com.devsphinx.web.model.user.CreateAccountModel;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.validation.Valid;

@Controller
public class CreateAccountController extends BaseController {

    @RequestMapping(value = "/create-account", method = RequestMethod.GET)
    public String getCreateAccount(Model model) {

        if (!model.containsAttribute("createAccountModel")) {
            model.addAttribute("createAccountModel", new CreateAccountModel());
        }

        return "create-account/create-account";
    }

    @RequestMapping(value = "/create-account", method = RequestMethod.POST)
    public String postCreateAccount(
            @Valid CreateAccountModel createAccountModel,
            BindingResult result, RedirectAttributes redirectAttributes) {

        if (result.hasErrors()) {
            redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.createAccountModel", result);
            redirectAttributes.addFlashAttribute("createAccountModel", createAccountModel);
            return "redirect:/create-account";
        }
        
        // Success case omitted...
    }
}

You can see that we have here a standard spring controller with two methods. The first method serves the GET request for the account creation page and the second one serves the POST request.

What we wanted to achieve is if the POST request is performed and there are validation errors, then the request is redirected to the GET handler with the errors and form field values still populated.

In the POST handler method

if (result.hasErrors()) {
    redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.createAccountModel", result);
    redirectAttributes.addFlashAttribute("createAccountModel", createAccountModel);
    return "redirect:/create-account";
}

In this, we have to populate these to the RedirectAttributes instance.

  • For the BindingResult you have to specify the class with the full package name and contatenate the model’s name to the end.
  • The model must be added with the same name as you were using in this method.

In the GET handler method

@RequestMapping(value = "/create-account", method = RequestMethod.GET)
public String getCreateAccount(Model model) {

  if (!model.containsAttribute("createAccountModel")) {
    model.addAttribute("createAccountModel", new CreateAccountModel());
  } 

  return "create-account/create-account";
}

If we redirect from the POST handler, because we added the flash attributes, the model in the GET handler will be automatically populated with these.

However, if we reach the GET handler with just a regular page request, without anything added as flash attributes, we need to manually add the our form backing object (createAccountModel) to the model.

Best way to validate decimal / double values with Spring

Spring’s validation support is widely used to validate objects. For example, it can validate models that are coming from user submitted forms. Validation is happening based on annotations that you can put on the fields in your model. These annotations are not part of Spring, external libraries must be used. The most common is the javax.validation package with the hibernate validator implementation.

The values to be validated could be decimal values. These can be represented by a number of different types. Probably the two most common types that pop into your mind are float and double. These could work okay, but because they are not exact numbers, just approximations, depending on the validation implementation, there could be some false results.

The best idea for validation is to use the BigDecimal type with the @DecimalMin and @DecimalMax validation annotations.

@DecimalMin(value = "0.1", inclusive = true)
@DecimalMax(value = "9.9", inclusive = true)
private BigDecimal measurement;

It might seem like a hassle to deal with values of this type, but actually it’s pretty straightforward. You just have to use method calls instead of numeric operators to add / subtract / etc. values.

 

Setting up a basic Spring Boot web application with Maven

In this tutorial I am going to show you, how to set up a basic web application using Spring Boot and Maven. The web application will have a single “home” page, rendered using a spring controller and a jsp file.

spring-by-pivotal

Technologies used in this tutorial:

  • Apache Tomcat 8.0.35
  • Apache Maven 3.3.9
  • Java 1.8.0_60

The structure of the project

Here you can see the file structure of the completed project:

structure-jtuts-2016-05-20-boot

Setting up the POM file

A basic Spring Boot web application requires very little configuration in the POM. We only have to include one dependency (apart from the servlet api needed for using jsp views). This is the spring-boot-starter-web, that transitively contains all other dependencies that are required for the spring controllers, logging etc.

<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>jtuts</groupId>
    <artifactId>jtuts-2016-05-20-setting-up-basic-spring-boot-web-app-with-maven</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>
    <name>Setting up a basic Spring Boot web application with Maven</name>

    <properties>

        <!-- Dependency versions -->

        <spring.boot.version>1.3.5.RELEASE</spring.boot.version>
        <servlet.api.version>3.1.0</servlet.api.version>

        <!-- Plugin versions -->

        <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>

        <!-- Misc versions -->

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

    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>

        <!-- Provided dependencies -->
        
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.api.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>



    <build>
        <finalName>boot-web-app</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

In the plugin configuration there is nothing Boot specific. We just set the Java version using the maven-compiler-plugin and also set the failOnMissingWebXml to false, because we deliberately don’t have a web.xml file.

The application runner class

A spring boot application can be initialized by a very simple class containing a main method.

package com.jtuts.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.jtuts")
public class Application extends SpringBootServletInitializer {

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

}

Note, that we have the @SpringBootApplication annotation, which is actually is a shorthand for the following ones:

  • @Configuration marks the class as a source of bean definitions for the application context.
  • @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
  • @EnableWebMvc is automatically added when Boot sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
  • @ComponentScan tells Spring to look for other components, configurations.

The  @Component annotation is automatically added, but by default it only looks for components in the current package, so we needed to override it, to look for components in the parent package. This way, it’ll see our controller also.

Extending the SpringBootServletInitializer is required to be able to deploy the application as a war file to a container (e.g. Tomcat). It is actually an implementation of the WebApplicationInitializer interface, that you would use when you want to create a web application without Boot.

That’s it for the application startup.

Creating the controller

Our controller is plain and simple, just returns a view without passing any parameters.

package com.jtuts.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {

    private static final String HOME = "home";

    @RequestMapping(value = HOME)
    public ModelAndView home() {
        return new ModelAndView(HOME);
    }
}

For this controller to work, we also have to specify a view resolver in a configuration class, that tells Spring where to find the view files based on their names.

package com.jtuts.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
public class ViewConfiguration {

    private static final String VIEW_PATH = "/WEB-INF/views/";
    private static final String JSP_EXTENSION = ".jsp";

    @Bean
    public ViewResolver setupViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();

        resolver.setPrefix(VIEW_PATH);
        resolver.setSuffix(JSP_EXTENSION);

        return resolver;
    }

}

Our view file

The view file is just a really simple one:

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Home page</title>
</head>
<body>
    <h1>Welcome to the home page.</h1>
</body>
</html>

How to launch the app

To launch this application, you just have to copy the war file created during build to a Tomcat container.

Additional notes

As you can see, a logback.xml is also included. This is because Spring Boot by default expects the logback configuration and the app would fail to start without that. The exact logging configuration is not really relevant to this tutorial, but anyway, here is the content of that file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

Download

You can download the working example project here.

Creating a Spring MVC Maven web application with Java config from scratch

This tutorial describes how to create a simple Spring MVC web application statring from a basic Maven project. We set up the required directories and files by hand, almost nothing will be pre-generated. For configuration we use only java classes and no XML files (except for the pom.xml for Maven, of course).

Tools used:

  • Spring Tool Suite 3.7.3.RELEASE
  • Apache Maven 3.3.9
  • Java 8 (Update 60)
  • Tomcat 8.0.32

Looking for an XML configuration solution?

We have an article on that as well. You can check it out here: Creating a Spring MVC Maven web application from scratch.

Creating the Maven project

  1. In STS press Ctrl + N, this brings up the New wizard where you select what kind of project or file you would like to create. In the search box enter maven. From the filtered list select Maven Project.
  2. Click Next.
  3. Check the Create a simple project (skip archetype selection) checkbox.
  4. Click Next.
  5. Set the following properties:
    • Group Id: com.jtuts
    • Artifact Id: spring-mvc-maven-webapp-with-java-config-from-scratch
    • Packaging: war
    • Name: spring-mvc-maven-webapp-with-java-config-from-scratch
  6. Click Finish.

Of course the Group Id, Artifact Id and Name properties can be set to anything else, these are just example values. However the war value for the Packaging is mandatory, because we are creating a web application and the server which will run it (in our case Tomcat) expects a .war file.

The directory structure

STS will automatically create the basic directory structure for our application. This conforms to the basic structure that Maven expects. You can find more information about it on Maven’s Introduction to the Standard Directory Layout page.

The most important directories for us are:

  • src/main/java: Java source files.
  • src/main/resources: Other resources like property files and xml files.
  • src/main/webapp: Web application source files (e.g. JPSs, images, CSS files).
  • src/test/java: Test source files.
  • src/test/resources: Resources for tests.

By default, Maven expects you to have the above mentioned files in these directories. You can change this in Maven’s pom.xml but you should avoid it not to create confusion when other developers look at your project.

Here is what our final directory structure will look like:

directory-structure

The pom.xml

The pom.xml file is added automatically by STS when you create the Maven project. However, we made some additions that are needed for our webapp to work. This is what the final pom.xml looks like:

<?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.jtuts</groupId>
    <artifactId>spring-mvc-maven-webapp-with-java-config-from-scratch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>spring-mvc-maven-webapp-with-java-config-from-scratch</name>

    <properties>

        <!-- Dependency versions -->

        <spring.version>4.2.5.RELEASE</spring.version>
        <servlet.api.version>3.1.0</servlet.api.version>

        <!-- Plugin versions -->

        <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>

        <!-- Misc versions -->

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

    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.api.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <finalName>spring-mvc-maven-webapp-with-java-config-from-scratch</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

In this file we include all the dependencies that are required by our example project:

  • The spring-mvc dependency will include all Spring related functionality.
  • The javax.servlet-api depencdecy contains the interfaces and classes that enables us to use servlets in our application.

The finalName will be the name of the .war file that is created.

Then, we have two plugins:

  1. The maven-compiler-plugin configures the compilation process of Maven. In this case we set that our source code must be compatible with at least Java 1.8, and we want our compiled program to be executable with Java 1.8 and above.
  2. The maven-war-plugin  is just there to set the failOnMissingWebXml property to false, because otherwise STS would report an error that we don’t have a web.xml.

Creating our application initializer class

Our application needs a point of entry where it’s startup process begins. We set up an application initializer class for this purpose. In case of Java config we don’t have a web.xml, so we need to define the application initializtion related stuff in a class. A class, that implements the WebApplicationInitializer interface, and Spring will call it’s onStartup method, when starting up the application. We create this, and further configuration classes in the com.jtuts.configuration package.

package com.jtuts.configuration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {

        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(ApplicationConfiguration.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(DispatcherServletConfiguration.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));

        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

In this method we do the following:

  1. First we create a root WebApplicationContext for the application. This application context will contain and manage all the beans defined. We also tell the container the manage the lifecycle of this application context.
  2. In the following lines we create a dispatcher context. Based on this context, we create a servlet called DispatcherServlet and add it to the container. The job of the DispatcherServlet is to take an incoming URL and find the right combination of handlers (generally methods on Controller classes) and views (generally JSPs) that combine to form the page or resource that’s supposed to be found at that location.
  3. Then we set the loadOnStartup value. A value of >=0 means that the servlet is loaded when the web-app is deployed or when the server starts. A value < 0 means that the servlet is loaded whenever the container feels like. Also, the container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same loadOnStartup value.
  4. Finally, we map the DispatcherServlet to the root path (/). This makes it the default servlet, that means, that it will handle all requests that does not match another servlet’s mapping.

This completes the initialization process. But as you might have noticed, we have registered two classes. The ApplicationConfiguration will contain configuration for the application context and the DispatcherServletConfiguration will contain configuration for the dispatcher servlet. Let’s look at them in detail.

The DispatcherServletConfiguration class

package com.jtuts.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.jtuts.controller")
public class DispatcherServletConfiguration {

    @Bean
    ViewResolver setupViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");

        return resolver;
    }
    
}

In this class using the @ComponentScan annotation we configure the location of our Controller beans.

We also set up a view resolver that will determine how to map view names into JSP files. The prefix property’s value will be prepended to the name of every view we request and the suffix property’s value will be appended to the requested view name. For example if our controller returns the view name “login“, it will be mapped to the jsp: “/WEB-INF/views/login.jsp“.

The @EnableWebMvc is the same as the <mvc:annotation-driven /> in the XML version.  It enables a couple of spring features like mapping requests to controllers using the @RequestMapping annotation, validating form data with the @Valid annotation and so on.

The ApplicationConfiguration class

package com.jtuts.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter  {

}

This class will contain the configurations related to the application context. Anything that is not related directly to handling incoming requests. Currently it is empty.

The HomeController class

We have a very simple controller, that is mapped to the /home path, and returns the “home” view name.

package com.jtuts.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {
    
    @RequestMapping("home")
    public ModelAndView home() {
        return new ModelAndView("home");
    }
    
}

The home JSP

We have a very simple JSP for the home page. It only contains some basic content so we know that our application is running fine.

<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Spring MVC web application from scratch</title>
</head>
<body>
    <h1>Welcome to the home page.</h1>
</body>
</html>

The running application

When you deploy the application to a Tomcat8 server, it will show you the following result if you navigate to the homepage:

welcome-to-the-homepage

To deploy the application to a Tomcat8 server you just have to copy your .war file located in the target folder, into tomcat-installation-path\webapps . Then start up the server by launching startup.bat (windows) or startup.sh (linux).

Download

You can download the working project here.