Spring Boot Application with Jersey Rest End Points

Yesterday I received a requirement to create a JAVA Spring Boot Application with Jersey Rest end-points. Researching on Internet about how to overwrite the SB configuration I founded that it solves with only one dependency!

So, here is a little example about how to configure and test (with Mockito and EasyMock) a Jersey end-point in a Spring Boot Application.

Steps/Tips

Add the Spring Boot starter Maven dependency for Jersey to your pom.xml

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

Add the configuration bean to include the Jersey’s Controller (classes or packages)

package com.example.sb.jersey.config;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

import com.example.sb.jersey.controller.ExampleController;

/**
 * Configuration class for Jersey controllers.
 * @author Gabriel
 *
 */
@Configuration
public class JerseyAppConfig extends ResourceConfig {
    public JerseyAppConfig() {
    	// you can map the packages
    	// packages("com.example.sb.jersey");
    	// or you can map each controller
        register(ExampleController.class);
    }
}

Replace the default Spring Boot annotations with Jersey annotations for the rest end-points

package com.example.sb.jersey.controller;

import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import com.example.sb.jersey.service.ExampleService;

/**
 * Handles the resource requests.
 * @author Gabriel
 *
 */
@Component
@Path("/resources")
public class ExampleController {

	private static final Logger LOGGER = LoggerFactory.getLogger(ExampleController.class);
	
	@Autowired
	private ExampleService exampleService;
	
	/**
	 * Gets a list of configured resources (queues and/or topics) for the application.
	 * @return
	 */
	@GET
	@Produces(MediaType.APPLICATION_JSON_VALUE)
	@Path("/get/test")
	public ResponseEntity<Map<String,String>> getConfiguredResources() {
		LOGGER.info("getConfiguredResources - start");
		
		Map<String,String> configuredResources = exampleService.getConfiguredResources();
		
		LOGGER.info("getConfiguredResources - end");
		return new ResponseEntity<Map<String,String>>(configuredResources, HttpStatus.OK);
	}
}

Unit Test for the Controller with Mockito for Spring Boot 1.4 or higer

package com.example.sb.jersey.controller;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.sb.jersey.controller.ExampleController;
import com.example.sb.jersey.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.equalTo;

@RunWith(SpringRunner.class)
public class ExampleControllerTest {

	@Rule
	public ExpectedException thrown = ExpectedException.none();
	
	@MockBean
	ExampleService exampleServiceMock;
	
	@SpyBean // use inject mocks with spring boot versions lower than 1.4
	private ExampleController exampleController;
	
	private Map<String, String> configuredResources;
	
	@Before
	public void setUp() {
		configuredResources = new HashMap<>();
		configuredResources.put("1", "resource #1");
		configuredResources.put("2", "resource #2");
		configuredResources.put("3", "resource #3");
		configuredResources.put("4", "resource #4");
		configuredResources.put("5", "resource #5");
	}
	
	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithListOfConfiguredResources() {
		Mockito.doReturn(configuredResources).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(configuredResources.size()));
	}
	
	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithNullListOfConfiguredResources() {
		Mockito.doReturn(null).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), nullValue());
	}

	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithEmptyListOfConfiguredResources() {
		Mockito.doReturn(new HashMap<>()).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(0));
	}	
}

Unit Test for the Controller with Mockito for Spring Boot 1.3.8 or lower

package com.example.sb.jersey.controller.oldmockito;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.sb.jersey.controller.ExampleController;
import com.example.sb.jersey.service.ExampleService;

import static org.hamcrest.MatcherAssert.assertThat;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.equalTo;

public class ExampleControllerTest {

	@Mock
	ExampleService exampleServiceMock;
	
	@InjectMocks // use inject mocks with spring boot versions lower than 1.4
	private ExampleController exampleController = new ExampleController();
	
	private Map<String, String> configuredResources;
	
	@Before
	public void setUp() {
		configuredResources = new HashMap<>();
		configuredResources.put("1", "resource #1");
		configuredResources.put("2", "resource #2");
		configuredResources.put("3", "resource #3");
		configuredResources.put("4", "resource #4");
		configuredResources.put("5", "resource #5");
		
		MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithListOfConfiguredResources() {
		Mockito.doReturn(configuredResources).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(configuredResources.size()));
	}
	
	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithNullListOfConfiguredResources() {
		Mockito.doReturn(null).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), nullValue());
	}

	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithEmptyListOfConfiguredResources() {
		Mockito.doReturn(new HashMap<>()).when(exampleServiceMock).getConfiguredResources();
		
		ResponseEntity<Map<String,String>> result = exampleController.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.getStatusCode(), equalTo(HttpStatus.OK));
		assertThat(result.getBody(), notNullValue());
		assertThat(result.getBody().size(), equalTo(0));
	}	
}

Unit Test for the Controller with EasyMock 3.4

package com.example.sb.jersey.service.easymock;

import org.easymock.EasyMockRunner;
import org.easymock.TestSubject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.example.sb.jersey.service.ExampleService;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

@RunWith(EasyMockRunner.class)
public class ResourceServiceTest {

	@TestSubject
	private ExampleService exampleService = new ExampleService();
	
	private Map<String, String> configuredResources;
	
	@Before
	public void setUp() {
		configuredResources = new HashMap<>();
		configuredResources.put("1", "resource #1");
		configuredResources.put("2", "resource #2");
		configuredResources.put("3", "resource #3");
	}
	
	@Test
	public void getConfiguredResourcesWithValidArgumentsShouldReturnAResponseEntityWithListOfConfiguredResources() {
		Map<String,String> result = exampleService.getConfiguredResources();
		
		assertThat(result, notNullValue());
		assertThat(result.size(), equalTo(configuredResources.size()));
	}
}

Final notes
The application was tested with Spring Boot versions: 1.5.3.RELEASE, 1.4.2.RELEASE and 1.3.8.RELEASE (without ServletInitiliazer class)

You can get all the code from my public GitHub repository:
https://github.com/Gabotto/SpringBootWithJerseyApp

Let me know if you have any problem, comment or new ideas:

WordPress: https://gabelopment.wordpress.com/
Email: gabelopment@gmail.com

See you soon with more development notes…

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s