Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Functional Programming in Spring MVC

DZone 's Guide to

Functional Programming in Spring MVC

Want to learn more about functional programming in Spring MVC?

· Java Zone ·
Free Resource

Spring 5.0 embraced the ReactiveStreams specification and introduced a new Reactive Stack as an alternative to the traditional Servlet stack. And, it also brought a new functional programming model to developers, but it is only supported in the Reactive Stack.

The good news is that, in the coming 5.2, the functional-like APIs are being ported back to the Servlet stack. For those developers who are stuck on Servlet stack and want to experience the new programming model, it is absolutely startling news.

In this post, let’s take a glance at the new functional feature in Spring MVC.

Create a Spring Boot project using Spring initializr (http://start.spring.io), add Web, JPA, Lombok, and H2 starters as dependencies.

NOTE: Please select the new Spring Boot version 2.2.0.BUILD-SNAPSHOT to get the new Spring 5.2.M1 in its dependencies.

Create a simple JPA Entity Post.

@Data@ToString@Builder@NoArgsConstructor@AllArgsConstructor@Entityclass Post {    
  @Id    @GeneratedValue(strategy = AUTO)    
  private Long id;    
  private String title;    
  private String content;
}


And create a Repository for the Post Entity.

interface PostRepository extends JpaRepository<Post, Long> {}


Define a RouterFuncation bean to handle the routing rules.

@Beanpublic RouterFunction<ServerResponse> routes(PostHandler postController) {    
  return route(GET("/posts"), postController::all)        
    .andRoute(POST("/posts"), postController::create)        
    .andRoute(GET("/posts/{id}"), postController::get)        
    .andRoute(PUT("/posts/{id}"), postController::update)        
    .andRoute(DELETE("/posts/{id}"), postController::delete);
}


The code is almost the same as the ones we have used in Reactive stack, but note here the ServerRequest, ServerResponse, and RouterFunction are imported from the new package:org.springframework.web.servlet.function.

Let’s have a look at the details of PostHandler.

@Componentclass PostHandler {    
  private final PostRepository posts;    
  public PostHandler(PostRepository posts) {        
    this.posts = posts;    }    
  public ServerResponse all(ServerRequest req) {        
    return ServerResponse.ok().body(this.posts.findAll());    }    
  public ServerResponse create(ServerRequest req) 
    throws ServletException, IOException {        
    var saved = this.posts.save(req.body(Post.class));        
    return ServerResponse.created(URI.create("/posts/" + saved.getId())).build();    }    
  public ServerResponse get(ServerRequest req) {        
    return this.posts.findById(Long.valueOf(req.pathVariable("id")))            
      .map(post -> ServerResponse.ok().body(post))            
      .orElse(ServerResponse.notFound().build());    }    
  public ServerResponse update(ServerRequest req) 
    throws ServletException, IOException {        var data = req.body(Post.class);        return this.posts.findById(Long.valueOf(req.pathVariable("id")))            .map(                post -> {                    post.setTitle(data.getTitle());                    post.setContent(data.getContent());                    return post;                }            )            .map(post -> this.posts.save(post))            .map(post -> ServerResponse.noContent().build())            .orElse(ServerResponse.notFound().build());    }    public ServerResponse delete(ServerRequest req) {        return this.posts.findById(Long.valueOf(req.pathVariable("id")))            .map(                post -> {                    this.posts.delete(post);                    return ServerResponse.noContent().build();                }            )            .orElse(ServerResponse.notFound().build());    }}


It is very similar to the codes of Reactive Stack, and but the methods return a ServerResponse instead of Mono<ServerResponse>.

Like the RouterFunctionDSL feature provided in Reactive Stack, the routing rules can also be written in Kotlin DSL.

router {        
  "/posts".nest {            
    GET("", postHandler::all)            
      GET("{id}", postHandler::get)            
      POST("", postHandler::create)            
      PUT("{id}", postHandler::update)            
      DELETE("{id}", postHandler::delete)        
  }    
}


Besides these, MockMvc also gets the support of Kotlin DSL; you can write your tests in a fluent style like the following.

@Test  fun `Get all posts should ok`() {        
  mockMvc                
    .get("/posts") {                    
    accept = APPLICATION_JSON headers {                        
      contentLanguage = Locale.ENGLISH                    
    }                
  }.andExpect {                    
    status { isOk }                    
    content { contentType(APPLICATION_JSON_UTF8) }                    
    jsonPath("$[0].title") { value(containsString("post")) 
                           }                 
  }                
  .andDo {                    
    print()                
  }    
}


Check out the source code from my GitHub and compare it with the code that I had written to demonstrate Reactive Stack.

Topics:
spring ,functional programming ,fp ,Java ,Spring MVC ,servlet ,reactive stack ,servlet stack

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}