Ralf Wehner's Blog

Just another WordPress.com weblog

Combining vaadin and classic spring mvc into one simple spring-boot application

with 2 comments

vaadin, a Java web framework.

As part of my freelance work one day i’ve noticed the very cool project vaadin which is based on google’s GWT and helps to create powerful web applications that will run on differnt browsers and devices. Building a web application with vaadin is analogue to build a SWING or Java FX application. You will create the “pages” (UIs) only in JAVA code and use layout objects e.g. the vertical layout to arrange all widgets like input fields, buttons, borders, labels, views, etc. on your page. There is no need to bother with HTML, javascript or css when you start writing your application, you can simply concentrate in implementing your business logic.

How does it work? When the user navigates to the vaadin application the server provides a JAVA SCRIPT that is loaded and running on the browser to renders the application page. All user actions will be syncronized to the server via RCP (AJAX GET and PUT) calls that will exchange information in JSON form and to the server. In user’s point of view a vaadin application behaves and feels like a native program, for example a rich client written in JAVA SWING. But in differnce to this it will simply run in your browser and there is no need to install software before. It is very impressive what huge functionlity you will get without the effort to search and embed JAVA-SCRIPT elements or code like jquery plugins. To get a better understanding how vaadin works, please have a look a the vaadin book which describes the framework well. The vaadin user interface will show you losts of useful widgets, layouts, databindings, concepts and addons and the corresponding source code and documentation.

What i want to do

Because i am a great fan of spring, especially spring-web-mvc, i want to find out a solution how to integrate a more or less complex vaadin application within a spring mvc application.  So the result have to

  • contain a spring mvc dispatcher servlet which provides the classic html pages,
  • the vaadin servlet used to serve the vaadin application and
  • it should be deployed as a simple war file, running within a tomcat or standalone.

Lets start

Before we start, all source code of this demo is hosted on github and can be cloned from here.

To be able run the application stanalone and within a simple web container like tomcat or jetty, i decided to used the new spring-boot project.

When starting a spring boot application, spring-boot determines the classpath and tries to find out which components are present. It loads the main application class, looks for the spring configuration, determines classes in packages and its annotations and looks for files in conventional pathes like application.properies or logback.xml etc. To pull up the vaadin servlet in combination with spring-boot i integrated the brand new vaadin4spring project into my classpath which makes it very easy to add UIs into the vaadin application.

The vaadin4spring project

First, checkout the project from github and install the artifacts into your local repository.

$ # cd into a directory where you want to checkout the vaading4spring project
$ git clone https://github.com/peholmst/vaadin4spring
$ cd vaading4spring
$ mvn install -DskipTests

The project comes with some example projects that are worth to open and have a look.

I think it is only a matter of time when this project will be published into spring’s or the global maven repositories so you can avoid cloning and building this project locally. But currently, it is necessary.

The demo application

maven’s pom.xml

Our demo application starts with a pom.xml which contains the dependencies to the vaadin4spring project, to spring-mvc, spring-boot and the spring-boot-maven-plugin. The spring-boot-maven-plugin is responsable to start the application from the shell, simply typing mvn spring-boot:run.

<?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>de.wehner.demo.vaadin</groupId>
    <artifactId>vaadin-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>vaadin-demo</name>
    <description>Vaadin Demo project</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <!-- spring boot for mvc and thymeleaf -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- spring boot for vaadin, see: https://github.com/peholmst/vaadin4spring -->
        <dependency>
            <groupId>org.vaadin.spring</groupId>
            <artifactId>spring-boot-vaadin</artifactId>
            <version>0.0.3-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-themes</artifactId>
            <version>7.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-client-compiled</artifactId>
            <version>7.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>runtime</scope>
        </dependency>

    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <start-class>demo.vaadin.Application</start-class>
        <java.version>1.7</java.version>
    </properties>

    <build>
        <plugins>
            <!-- spring-boot-maven-plugin used to start application in debugging mode
                on port 8000 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
<!--                 <configuration>
                    <jvmArguments> -Xdebug
                        -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
                    </jvmArguments>
                </configuration>-->
            </plugin>
        </plugins>
    </build>

</project>

The main configuration file application.properties

The application.properties is placed in folder /src/main/resources and contains the URL mapping for all requests that are intended for the vaadin servlet. This is important for a clear separation which servlet have to process a request, the VaadinServlet or spring’s DispatcherServlet.

vaadin.servlet.urlMapping=/myUI/*

# Allow Thymeleaf templates to be reloaded at dev time
spring.thymeleaf.cache: false
server.tomcat.access_log_enabled: true
server.tomcat.basedir: target/tomcat
#logging.level.org.springframework.security: INFO

The main application and the spring configuration class

The main application class Application also contains the spring configuration, configures spring-boot using the SpringApplicationBuilder class and starts up the spring boot process. It is referred in mavens  pom.xml to specify the application’s main class, see <start-class>demo.vaadin.Application</start-class>.

package demo.vaadin;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages="demo")
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder().sources(Application.class).web(true)
                .logStartupInfo(true).showBanner(true).run(args);
    }
}

The vaadin UI class

Using the vaadin4spring project it is very simple to integrate a vaadin UI-classes into the vaadin servlet. Just implement the abstract UI class and add the annotation @VaadinUI to the class. Here is one of the two UIs i have implemented into the demo application:

package demo.vaadin;

import org.vaadin.spring.VaadinUI;

import com.vaadin.server.ExternalResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.UI;

@VaadinUI(path = "/simple")
public class SimpleVaadinUI extends UI {

    private static final long serialVersionUID = 1L;

    @Override
    protected void init(VaadinRequest vaadinRequest) {

        Label label = new Label("Hello! I'm another simple UI!");
        Link linkToSpring = new Link("Back to spring's Thymeleaf",
                new ExternalResource("/"));

        AbsoluteLayout absoluteLayout = new AbsoluteLayout();
        absoluteLayout.addStyleName("outlined");
        absoluteLayout.setSizeFull();

        absoluteLayout.addComponent(label, "top:10px; left:10px");
        absoluteLayout.addComponent(linkToSpring, "top: 100px; left: 50px");

        setContent(absoluteLayout);
    }
}

You will access the application in your browser when opening the URL http://localhost:8080/myUI/simple. The url is a combination of the vaadin.servlet.urlMapping property and the path attribute in @VaadinUI.

Adding spring-mvc functionality

To add the spring-mvc functionality according to spring-boot you only have to implement a Controller class with @Controller and @RequestMapping annotation and add the spring-boot-starter-web or spring-boot-starter-thymeleaf artifact to the project.

For this demo i have used a sample code which comes directly from spring-boot project is written by Rob Winch and taken from the example spring-boot-sample-web-ui.

package demo.ui.controller;

import ...
...
/**
 * @author Rob Winch
 */
@Controller
@RequestMapping("/")
public class MessageController {
    private final MessageRepository messageRepository;

    @Autowired
    public MessageController(MessageRepository messageRepository) {
        this.messageRepository = messageRepository;
    }

    @RequestMapping
    public ModelAndView list() {
        Iterable<Message> messages = this.messageRepository.findAll();
        return new ModelAndView("messages/list", "messages", messages);
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView create(@Valid Message message, BindingResult result,
            RedirectAttributes redirect) {
        if (result.hasErrors()) {
            return new ModelAndView("messages/form", "formErrors", result.getAllErrors());
        }
        message = this.messageRepository.save(message);
        redirect.addFlashAttribute("globalMessage", "Successfully created a new message");
        return new ModelAndView("redirect:/{message.id}", "message.id", message.getId());
    }
...
}

The spring-web-mvc part uses Thymeleaf as a template engine to create the HTML output. It is a very good alternative concept to the classic jsp technologie.

Source code and demo application

As mentioned at the beginning of this blog the source code is available in project spring-boot-vaadin-demo on github. For the impatience a running demo application can be downloaded here.

$ cd /tmp
$ wget https://s3.amazonaws.com/rwe-public/vaadin-demo-0.0.1-SNAPSHOT.war
$ java -jar target/vaadin-demo-0.0.1-SNAPSHOT.war

After you have received the war file and started the application you will see the demo in your browser using this url: http://localhost:8080/.

Written by rwehner

August 26, 2014 at 9:34 pm

Create JSON response for AJAX request in spring 3.0

with 8 comments

Within a project pause i was playing with the google chart tools embedded within a spring 3 web project which impressed me well.
After playing with some charts i reached a point were it was usedful to fill the TableData Java script object with data provided by an AJAX request. What i needed was to implent a simple own Data Source.
Using the actual spring 3.0 version i found out two simple solutions to generate a JSON response for AJAX requests.

Use Jackson JSON processor in combination with spring’s StringHttpMessageConverter

I used the Jackson JSON processor to generate a JSON string that can be written via the spring’s StringHttpMessageConverter into the HttpServletResponse response object. To use this functionality we have to add the jackson-mapper-asl.jar into our project. For maven projects we have to add following stuff into the pom.xml dependencies:

		<!-- Jackson JSON Mapper -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.5.3</version>
		</dependency>

The Jackson processor provides two ways to generate a JSON object stream:

Simple Data Binding

You can use Map objects to build the JSON object graph and generate the JSON stream. In a spring web controller this could look like this:

@Controller
public class RestController {

    @RequestMapping(value = "rest/playground/json-user", method = RequestMethod.GET)
    protected void getJsonDataExampleSimpleDataBinding(HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String> nameStruct = new HashMap<String, String>();
        nameStruct.put("first", "Joe");
        nameStruct.put("last", "Sixpack");
        Map<String, Object> userData = new HashMap<String, Object>();
        userData.put("name", nameStruct);
        userData.put("gender", "MALE");
        userData.put("verified", Boolean.FALSE);
        userData.put("userImage", "Rm9vYmFyIQ==");
        String jsonString = mapper.writeValueAsString(userData);

        AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {
            try {
                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }
    ...
}

Full Data Binding

In opposite to use Map objects often it makes sense to represent the JSON objects in simple bean classes (POJOs) on the server side and to marshall the POJO back to a JSON string stream. Here is an example:

    @RequestMapping(value = "rest/playground/json-user", method = RequestMethod.GET)
    protected void getJsonDataExampleFullDataBinding(HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Object userData = new String("mock for the json object which have to be replaced with real one");
        String jsonString = mapper.writeValueAsString(userData);

        AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {
            try {
                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }

Beside the simple data binding and full data binding there exists two other JSON processing variantes named as Streaming and Tree model. Please have a look at the documentation if you need more information on how to use Jackson.

Use the spring’s MappingJacksonHttpMessageConverter

Another solution to provide JSON response is to use the MappingJacksonHttpMessageConverter which is an implementation of HttpMessageConverter that can read and write JSON using the Jackson’s ObjectMapper. (Underneath the cover the MappingJacksonHttpMessageConverter uses Jackson as the name implied.) For propper use of this Implementation we have to add the depending artifact jason-mapper-asl.jar into our project as shown in the pom.xml example above.

Use the MappingJacksonHttpMessageConverter directly in controller’s request method

Use the MappingJacksonHttpMessageConverter class directly in the controler’s request method to build the HttpServeletResponse. This will be show in the example below:

    @RequestMapping(value = "rest/playground/json-example", method = RequestMethod.GET)
    protected void getJsonDataExample(HttpServletResponse response) {
        MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        Object jsonBean = new String("mock for the json object which have to be replaced with real one");
        if (jsonConverter.canWrite(jsonBean.getClass(), jsonMimeType)) {
            try {
                jsonConverter.write(jsonBean, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }

In this code the JSON object is represented in a POJO on the server side and will be serialized and processed into ‘application/json’ response by the MappingJacksonHttpMessageConverter. When it becomes necessary to have more control about the serialization/deserialization process a custom-configured ObjectMapper can be set using the method MappingJacksonHttpMessageConverter.setObjectMapper().

Use the @ResponseBody Annotation

A very simple solution is to use the spring’s @RequestBody Annotation on the return value of a controller method. When using the @RequestBody the return value is indicated to be bound to a web response body which will be automatically done by the spring MVC. In this case, Spring MVC invokes a MappingJacksonHttpMessageConverter built on the Jackson JSON processor. This implementation is enabled automatically when you use the mvc:annotation-driven configuration element with Jackson present in your classpath.
So, an approch in code can look like this:

    @RequestMapping(value = "/rest/playground/google-barchart", method = RequestMethod.GET)
    public @ResponseBody
    GoogleJsonResponse getJsonDataForBarChart(HttpServletResponse response, HttpServletRequest request) {
        response.setStatus(HttpServletResponse.SC_OK);
        GoogleJsonResponse ret = new GoogleJsonResponse();
        ret.addColl("string", "Year");
        ret.addColl("number", "Austria");
        ret.addColl("number", "Bulgaria");
        ret.addColl("number", "Denmark");
        ret.addColl("number", "Greece");
        ret.addRow(new GoogleJsonResponse.Cell("2003"), new GoogleJsonResponse.Cell(1336060), new GoogleJsonResponse.Cell(400361), new GoogleJsonResponse.Cell(1001582), new GoogleJsonResponse.Cell(
                997974));
        ret.addRow(new GoogleJsonResponse.Cell("2004"), new GoogleJsonResponse.Cell(1538156), new GoogleJsonResponse.Cell(366849), new GoogleJsonResponse.Cell(1119450), new GoogleJsonResponse.Cell(
                941795));
        ret.addRow(new GoogleJsonResponse.Cell("2005"), new GoogleJsonResponse.Cell(1576579), new GoogleJsonResponse.Cell(440514), new GoogleJsonResponse.Cell(993360), new GoogleJsonResponse.Cell(
                930593));
        ret.addRow(new GoogleJsonResponse.Cell("2006"), new GoogleJsonResponse.Cell(1600652), new GoogleJsonResponse.Cell(434552), new GoogleJsonResponse.Cell(1004163), new GoogleJsonResponse.Cell(
                897127));
        ret.addRow(new GoogleJsonResponse.Cell("2007"), new GoogleJsonResponse.Cell(1968113), new GoogleJsonResponse.Cell(393032), new GoogleJsonResponse.Cell(979198), new GoogleJsonResponse.Cell(
                1080887));
        ret.addRow(new GoogleJsonResponse.Cell("2008"), new GoogleJsonResponse.Cell(1901067), new GoogleJsonResponse.Cell(517206), new GoogleJsonResponse.Cell(916965), new GoogleJsonResponse.Cell(
                1056036));
        return ret;
    }

(I’ve modified a google tool chart example and created the GoogleJsonResponse class which is a simple Java bean with some attributes and setter and getter. This class represents the JSON data that will be wrapped into a google TableData objects in the java script of the jsp.)

public class GoogleJsonResponse {

    class Col {
        String id;
        final String _type;
        final String _label;

        public Col(String type, String label) {
            _type = type;
            _label = label;
        }

        public String getId() {
            return id;
        }

        public String getType() {
            return _type;
        }

        public String getLabel() {
            return _label;
        }
    };

    public static class Cell {
        private final Object _v;

        public Cell(Object v) {
            _v = v;
        }

        public Object getV() {
            return _v;
        }
    }

    class Row {
        List<Cell> _c = new ArrayList<Cell>();

        public void addCells(Cell... cells) {
            _c.addAll(Arrays.asList(cells));
        }

        public List<Cell> getC() {
            return _c;
        }
    };

    /* GoogleResonResponse attributes starts here */
    private List<Col> _cols = new ArrayList<Col>();
    
    private List<Row> _rows = new ArrayList<Row>();

    public void addColl(String type, String label) {
        Col col = new Col(type, label);
        _cols.add(col);
    }

    public void addRow(Cell... cells) {
        Row row = new Row();
        row.addCells(cells);
        _rows.add(row);
    }

    public List<Col> getCols() {
        return _cols;
    }

    public List<Row> getRows() {
        return _rows;
    }
}

Conclusion

The simplest and most straightforward solution to generate an ‘application/json’ response seemed to me to use the @ResponseBody annotation as shown above. If you need more control about the serialization of the JSON bean objects on the server side, e.g. if you need a special representation of java.util.Date attributes, you have to use Annotations as described in Jackson Core documenation.

Written by rwehner

June 9, 2010 at 11:35 am

Posted in java, spring 3.0

A simple way to create git repository on a server machine connecting via ssh

with 12 comments

Situation:

Let’s assume following situation:

  • We have a folder ˜/workshop , that contains the project on a local machine
  • Our project folder workshop is not a git repository yet
  • We want to have a server that hosts the workshop project and new developer can get the repository using a ‘git clone …’ command
  • On server site, the new repository should be located unter ˜/gitrepos/workshop.git.

To simplify the following steps i will use the machine localhost as the server machine.

Create a working copy repository

First, create a new local git repository and add all files within this folder.

cd ˜/workshop
git init
git add .
git commit -m "initial repository creation"

Create the bare repository

Then we have to create a bare repository on the server side. Let’s assume the user ralfwehner is the repository admin user on server side. For this step i will show two alternative ways:
a) We clone the server’s repositiory on the client machine and copy it via scp up to the server:

git clone --bare .git ../workshop.git
scp -r ../workshop.git ralfwehner@localhost:/Users/ralfwehner/gitrepos/workspace.git

b) We create a new empty repository on the server side and copy the developer’s repository from client machine to server (recommended when using difference git versions on server and clients):
So, first create the bare repository on server side:

sudo -u ralfwehner mkdir -m 770 /Users/ralfwehner/gitrepos/workshop.git
cd /Users/ralfwehner/gitrepos/workshop.git
sudo -u ralfwehner git --bare init --shared=group

From client side the developer’s project must be pushed into the new bare server repository:

git remote add origin ssh://ralfwehner@dev-server/Users/ralfwehner/gitrepos/workshop.git
git push origin master

That’s it. The project ‘workshop’ is now available on the server and can be cloned using the git clone command. E.g.:

cd /tmp/
git clone ralfwehner@localhost:/Users/ralfwehner/gitrepos/workshop.git myclonedworkshop

Synconize local and server repositories

Push developers repository to server

To synchronize the changes checked in into the local developer’s project to the server repository:

git push

Pull or merge the server repository into developer’s one

This command synchronizes the server’s repository to the local developer’s one. By this step changes made from other developers that pushed their stuff up to the server will be merged into the local repository.

git pull . remotes/origin/master

Checkout a project from server

In git terminology the checkout of a projekt can be understood as a clone of a git repository from a server to the developer’s local machine. You can do this simply by:

mkdir myNewWorkspace && cd myNewWorkspace
git clone ssh://localhost/Users/ralfwehner/gitrepos/workshop.git

The new created project can be pushed and pulled with:

cd workshop
... do you changes...
git push
... merge changes made from other users...
git pull

Heads up for Mac OS X users as i’m, too

There is a problem using the ssh commands to connecto to the git server which can end in error messages like: ‘bash: git-upload-pack: command not found’ on some machines. I’ve found this article that describe the problem and the solution more precisely.

For short, the solution is to create the symbolic link .bashrc to the .profile file:

server$ cd ~
server$ ln -s .profile .bashrc

Written by rwehner

March 1, 2010 at 4:35 pm

Posted in git

Tagged with

Mockito – some programming examples

with 5 comments

My favorite mocking library in JAVA is Mockito. It is absolutely great!

So, in this post i want to show some programming examples how to use Mockito in your JUnit test code. I don’t want to write a tutorial or a howto, this is just a summary of programming examples for JAVA programmers who are familiar with Mockito.

Capturing method arguments from Mocks for further assertions:
If you are using the version 1.8 and above you can use the ArgumentCaptor. The ArgumentCapture gives you a way to get one or more Arguments of a mocked method that was called before. Use the ArgumentCapture only if need to evaluate complex objects or objects that were created outside your junit test code. If you just want to verify the proper call of a simple mocked method, its better to use a simple verify(mock).yourMethod(). This makes your test code more readable.

So, start working with ArgumentCaptures with code:

package de.wehner.mockito.samples;

import static org.junit.Assert.assertEquals;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class MockitoSampleTests {

    @Test
    public void testInvideJohn() {
        ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
        Party party = mock(Party.class);

        Person john = new Person("John");
        Person peter = new Person("Peter");

        // Peter invites John to the party
        peter.invideToParty(john, party);

        verify(party).addGuest(argument.capture());
        // verify John was invited
        assertEquals("John", argument.getValue().getName());
    }
}

And this is the Person:

package de.wehner.mockito.samples;

public class Person {

    private final String _name;

    public Person(String name) {
        super();
        _name = name;
    }

    public String getName() {
        return _name;
    }

    public void invideToParty(Person friend, Party party) {
        party.addGuest(friend);
    }
}

Another way to solve this problem is to use a helper class (here this this the Holder<>) that is final and must be used in combination with the BaseMatcher<> class from Mockito.

package de.wehner.mockito.samples;

import static org.junit.Assert.assertEquals;

import static org.mockito.Matchers.*;

import static org.mockito.Mockito.*;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.core.AnyOf;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

public class MockitoSampleTests {

    @Test
    public void testInvideJohn() {
        ...
    }

    public class Holder<T> {
        private T _value;

        public Holder() {
        }

        public Holder(T value) {
            _value = value;
        }

        public T get() {
            return _value;
        }

        public void set(T value) {
            _value = value;
        }
    }

    @Test
    public void testInvideJaneAndJohn() {
        Party party = mock(Party.class);
        Person peter = new Person("Peter");
        Person jane = new Person("Jane");
        Person john = new Person("John");

        // "listen" to invocations of Party.addGuest() method
        final Holder<Person> lastInvited = new Holder<Person>();
        doNothing().when(party).addGuest(argThat(new BaseMatcher<Person>() {

            @Override
            public boolean matches(Object arg0) {
                lastInvited.set((Person) arg0);
                return true;
            }

            @Override
            public void describeTo(Description arg0) {
            }
        }));

        // Peter invites his friends
        peter.invideToParty(jane, party);
        peter.invideToParty(john, party);

        // verify 2 guests are invited and John is the last one
        verify(party, times(2)).addGuest(any(Person.class));
        assertEquals(john, lastInvited.get());
    }
}

Written by rwehner

February 23, 2010 at 9:56 pm

Posted in java, JUnit

Tagged with , ,

Follow

Get every new post delivered to your Inbox.