8 new features you’ll get with Spring Boot 1.4

…and you won’t believe what happens next ;)
April 17, 2016 by Michael

Phil as a nice post about the improvements on testing in Spring Boot 1.4, check it out here: Testing improvements in Spring Boot 1.4.

I’d like to add a concrete example for those and some more, please have a look at the comments inside one of the most important controllers I’ve ever written 😉

Those are the dependencies you’ll need for the demo:

<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>
    <dependency> 
        <groupid>org.springframework.restdocs</groupid>
        <artifactid>spring-restdocs-mockmvc</artifactid>	    	    
        <scope>test</scope>
    </dependency>
</dependencies>

Here’s the complete demo application:

import java.io.IOException;
import java.io.PrintStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
 
@SpringBootApplication
public class Demo14Application {
 
    @Controller
    @RequestMapping("/api/banner")
    static class BannerController {
 
	// 1) If you didn't chose to disable banner in your application (and why
	//    should you? ;) ), the banner will be availabe as a bean in your 
	//    application
	// 2) banner.jpg :) You can replace banner.txt with a banner.jpg or banner.png
	//    to generate some nice ascii art during startup
	private final Banner banner;
 
	private final Environment environment;
 
	// 3) no more @Autowired on constructors necessary 
	//    when there's on a unique non-default constructor
	//    This also works on @Configuration classes, which didn't support 
	//    constructor injection at all so far.
	//    This comes actually from Spring Framework 4.3.RC1   
	public BannerController(final Banner banner, final Environment environment) {
	    this.banner = banner;
	    this.environment = environment;
	}
 
	// 4) More annotations ;) 
	//    Precomposed @GetMapping, @PostMapping, @RequestScope, @SessionScope etc
	@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
	public void get(final HttpServletResponse response) throws IOException {
	    try (PrintStream printStream = new PrintStream(response.getOutputStream())) {
		banner.printBanner(environment, BannerController.class, printStream);
	    }
	}
    }
 
    public static void main(String[] args) {
	SpringApplication.run(Demo14Application.class, args);
    }
}

And here’s the test. I really like the simplifications there:

import BannerController;
import java.io.PrintStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
 
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
// 5) Easier named JUnit Runner ;)
@RunWith(SpringRunner.class)
// 6) Test slices of your application, in this case the Spring MVC slice
//    similiar options are available for @DataJpaTest and @JsonTest (incuding
//    JacksonTester).
@WebMvcTest(controllers = BannerController.class)	
// 7) Together with the above auto configuration comes autoconfiguration of
//    Spring REST docs, which removes the need for the JUnit rule and additional
//    configuration of the mock mvc instance
//    BTW: It seams that you can use addtitional formats like markdown for the
//    snippets
@AutoConfigureRestDocs(
	outputDir = "target/generated-snippets",
	uriHost = "banner-as-a-service.io",
	uriPort = 80
)
public class Demo14ApplicationTests {
 
    // 8) Spring Boot includes a @MockBean annotation that can be used to define
    //    a Mockito mock for a bean inside your ApplicationContext. You can use 
    //    the annotation to add new beans, or replace a single existing bean 
    //    definition. 
    @MockBean
    private Banner banner;
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void testSomeMethod() throws Exception {
	doAnswer(invocation -> {
	    final PrintStream out = invocation.getArgumentAt(2, PrintStream.class);
	    out.write(bannerText.getBytes());
	    return null;
	}).when(banner).printBanner(anyObject(), anyObject(), anyObject());
 
	mockMvc
		.perform(
			get("/api/banner").accept(APPLICATION_JSON)
		)
		.andExpect(status().isOk())
		.andExpect(content().string(bannerText))
		.andDo(document("api/banner",
			preprocessRequest(prettyPrint()),
			preprocessResponse(prettyPrint())
		));
    }
 
    private final String bannerText
	    = " _____            _              ______ _____ _____ _____       _                \n"
	    + "/  ___|          (_)             | ___ \\  ___/  ___|_   _|     | |               \n"
	    + "\\ `--. _ __  _ __ _ _ __   __ _  | |_/ / |__ \\ `--.  | |     __| | ___   ___ ___ \n"
	    + " `--. \\ '_ \\| '__| | '_ \\ / _` | |    /|  __| `--. \\ | |    / _` |/ _ \\ / __/ __|\n"
	    + "/\\__/ / |_) | |  | | | | | (_| | | |\\ \\| |___/\\__/ / | |   | (_| | (_) | (__\\__ \\\n"
	    + "\\____/| .__/|_|  |_|_| |_|\\__, | \\_| \\_\\____/\\____/  \\_/    \\__,_|\\___/ \\___|___/\n"
	    + "      | |                  __/ |                                                 \n"
	    + "      |_|                 |___/                                                  \n"
	    + "          _ _   _        ___   _____ _____ _____ _____              _            \n"
	    + "         (_) | | |      / _ \\ /  ___/  __ \\_   _|_   _|            | |           \n"
	    + "__      ___| |_| |__   / /_\\ \\\\ `--.| /  \\/ | |   | |     __ _ _ __| |_          \n"
	    + "\\ \\ /\\ / / | __| '_ \\  |  _  | `--. \\ |     | |   | |    / _` | '__| __|         \n"
	    + " \\ V  V /| | |_| | | | | | | |/\\__/ / \\__/\\_| |_ _| |_  | (_| | |  | |_          \n"
	    + "  \\_/\\_/ |_|\\__|_| |_| \\_| |_/\\____/ \\____/\\___/ \\___/   \\__,_|_|   \\__|         \n"
	    + "                                                                                 \n"
	    + "                                                                                 ";
}

Have a look at the release notes or the updated reference documentation for more.

Thanks Josh for including my silly example in This Week in Spring once more, i love it:


thisweekinspring20160419

No comments yet

One Trackback/Pingback
  1. […] our other pal Michael Simons is back at it again this week, also with a look at the features in Spring Boot 1.4 […]

Post a Comment

Your email is never published nor shared. Required fields are marked *