I am learning Spring Boot, and am working with Spring WebFlux, and reactive Mongo DB. My controllers are working fine, but my tests are failing on null pointer exception.
My build.gradle is:
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'guru.springframework'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'junit:junit:4.12'
compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'
testCompileOnly 'org.projectlombok:lombok:1.18.16'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.16'
//testCompile group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '3.0.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
My Controller is:
package guru.springframework.spring5webfluxrest.controllers;
import guru.springframework.spring5webfluxrest.domain.Category;
import guru.springframework.spring5webfluxrest.repositories.CategoryRepository;
import org.reactivestreams.Publisher;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.concurrent.Flow;
#RestController
public class CategoryController {
private final CategoryRepository categoryRepository;
public CategoryController(CategoryRepository categoryRepository) {
this.categoryRepository = categoryRepository;
}
#GetMapping("/api/v1/categories")
public Flux<Category> list(){
return categoryRepository.findAll();
}
#GetMapping("/api/v1/categories/{id}")
public Mono<Category> getById(#PathVariable String id){
return categoryRepository.findById(id);
}
#ResponseStatus(HttpStatus.CREATED)
#PostMapping("/api/v1/categories")
public Mono<Void> create(#RequestBody Publisher<Category> categoryStream){
return categoryRepository.saveAll(categoryStream).then();
}
#PutMapping("/api/v1/categories/{id}")
public Mono<Category> update (#PathVariable String id, #RequestBody Category category){
category.setId(id);
return categoryRepository.save(category);
}
#PatchMapping("/api/v1/categories/{id}")
public Mono<Category> patch(#PathVariable String id, #RequestBody Category category){
Category foundCategory = categoryRepository.findById(id).block();
if(category.getDescription() != foundCategory.getDescription()){
foundCategory.setDescription(category.getDescription());
return categoryRepository.save(foundCategory);
}
return Mono.just(foundCategory);
}
}
My test is:
package guru.springframework.spring5webfluxrest.controllers;
import guru.springframework.spring5webfluxrest.domain.Category;
import guru.springframework.spring5webfluxrest.repositories.CategoryRepository;
import org.junit.Before;
import org.junit.Test;
//import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.mockito.Mockito;
import org.reactivestreams.Publisher;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
public class CategoryControllerTest {
WebTestClient webTestClient;
CategoryRepository categoryRepository;
CategoryController categoryController;
#Before
public void setUp() throws Exception {
categoryRepository = Mockito.mock(CategoryRepository.class);
categoryController = new CategoryController(categoryRepository);
webTestClient = WebTestClient.bindToController(categoryController).build();
}
#Test
public void list() {
given(categoryRepository.findAll())
.willReturn(Flux.just(Category.builder().description("Cat1").build(),
Category.builder().description("Cat2").build()));
webTestClient.get()
.uri("/api/v1/categories/")
.exchange()
.expectBodyList(Category.class)
.hasSize(2);
}
#Test
public void getById() {
given(categoryRepository.findById("someid"))
.willReturn(Mono.just(Category.builder().description("Cat").build()));
webTestClient.get()
.uri("/api/v1/categories/someid")
.exchange()
.expectBody(Category.class);
}
#Test
public void create() {
given(categoryRepository.saveAll(any(Publisher.class)))
.willReturn(Flux.just(Category.builder().description("descrp").build()));
Mono<Category> catToSaveMono = Mono.just(Category.builder().description("Some Cat").build());
webTestClient.post()
.uri("/api/v1/categories")
.body(catToSaveMono, Category.class)
.exchange()
.expectStatus()
.isCreated();
}
#Test
public void update() {
given(categoryRepository.save(any(Category.class)))
.willReturn(Mono.just(Category.builder().build()));
Mono<Category> catToUpdateMono = Mono.just(Category.builder().description("Some Cat").build());
webTestClient.put()
.uri("/api/v1/categories/asdfjkl")
.body(catToUpdateMono, Category.class)
.exchange()
.expectStatus()
.isOk();
}
#Test
public void testPatchNoChanges() {
given(categoryRepository.findById(anyString()))
.willReturn(Mono.just(Category.builder().build()));
given(categoryRepository.save(any(Category.class)))
.willReturn(Mono.just(Category.builder().build()));
Mono<Category> catToUpdateMono = Mono.just(Category.builder().build());
webTestClient.patch()
.uri("/api/v1/categories/asdfasdf")
.body(catToUpdateMono, Category.class)
.exchange()
.expectStatus()
.isOk();
verify(categoryRepository, never()).save(any());
}
}
Any help would be greatly appreciated.
Your test is annotated with the JUnit4's #Test annotation but you are trying to run it with JUnit5. JUnit5 cannot see it.
Uncomment the org.junit.jupiter.api.Test import and remove import org.junit.Test (CategoryControllerTest).
Remove implementation 'junit:junit:4.12' from the build.gradle as well.
Related
while creating a file upload api using spring webflux, the response of the api is 415.
I searched hard on Google, but couldn't find a solution, so I posted a question.
My guess is that the conversion of Flux files failed during the message conversion process.
I would be very grateful if you could tell me how to solve it.
I couldn't speak English well, so I had help from Google Translate. I apologize in advance that my tone may be unsporting.
environmental information
jdk17,
gradle 7.6
dependencies
dependencies {
// lombok
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.24'
annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.24'
// https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.2'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
API CODE Example
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#Slf4j
#RestController
#RequestMapping("/v1")
public class FileController {
#PostMapping(value = "/test")
public String test(#RequestPart("test") String temp) {
return null;
}
#PostMapping(value = "/file", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public Mono<ResponseEntity<String>> uploadFile(#RequestPart("file") Flux<FilePart> files) {
System.out.println("called uploadFile!!!");
return Mono.empty();
}
}
Test CODE Example
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.FileInputStream;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.mock.web.MockPart;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#ExtendWith(SpringExtension.class)
#SpringBootTest
public class FileControllerTest {
#Test
#DisplayName("file upload test")
public void uploadFileTest() throws Exception {
// given
String fileName = "TestSample";
String origFilename = "TestSample.md";
Path sampleFilePath = Paths.get(getClass().getResource("sample/" + origFilename + "").toURI());
FileInputStream fis = new FileInputStream(sampleFilePath.toFile());
MockMultipartFile sampleFile = new MockMultipartFile(fileName,
origFilename, MediaType.MULTIPART_FORM_DATA_VALUE, fis);
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new FileController()).build();
// when, then
mockMvc.perform(
multipart(new URI("/v1/file")).file(
sampleFile).part(
new MockPart("file",
sampleFile.getBytes())))
.andExpect(status().isOk());
}
}
Response Example
2023-02-02T11:45:45.114+09:00 WARN 36696 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/octet-stream' is not supported]
I'm creating telegram-bot. When I use longpolling-bot it works correct, but I can't create bot that works on webhooks - http-request don't reach endpoint that has been registered as webhook-url in telegram.
For local deployment I use ngrok application.
I'm trying to send POST-request using Postman, which simulates an http-request from telegram-server, but the requests don't reach the method org.telegram.telegrambots.updatesreceivers.RestApi::updateReceived
This is the code:
build.gradle
plugins {
id "java"
id "org.springframework.boot" version "3.0.1"
id "io.spring.dependency-management" version "1.1.0"
}
repositories {
mavenCentral()
mavenLocal()
}
group 'com.example'
sourceCompatibility = JavaVersion.VERSION_17
def telegramBotVersion = "6.3.0"
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.springframework.boot:spring-boot-starter'
implementation "org.telegram:telegrambots-spring-boot-starter:$telegramBotVersion"
implementation "org.telegram:telegrambotsextensions:$telegramBotVersion"
implementation 'javax.ws.rs:javax.ws.rs-api:2.0-m08'
implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359'
}
package com.example.telegram.bot;
import com.example.telegram.service.TelegramService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.extensions.bots.commandbot.TelegramWebhookCommandBot;
import org.telegram.telegrambots.meta.api.objects.Update;
#Slf4j
public class WebhookBot extends TelegramWebhookCommandBot {
private final String name;
private final String token;
public WebhookBot(String name, String token) {
this.name = name;
this.token = token;
}
#Autowired
private TelegramService telegramService;
#Override
public String getBotUsername() {
return name;
}
#Override
public String getBotToken() {
return token;
}
#Override
public String getBotPath() {
return "webhookurl";
}
#Override
public void processNonCommandUpdate(Update update) {
System.out.println("processNonCommandUpdate");
}
}
package com.example.telegram.config;
import com.example.telegram.bot.WebhookBot;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.telegram.telegrambots.bots.TelegramWebhookBot;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.api.methods.updates.SetWebhook;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
import org.telegram.telegrambots.updatesreceivers.DefaultWebhook;
#Configuration
#Profile("webhook")
#Slf4j
public class WebHookBotConfig {
#Value("${telegram.bot.name}")
private String name; //bot-name
#Value("${telegram.bot.token}")
private String token; //bot-token
#Value("${telegram.bot.webhook.uri}")
private String webhookUri; // https://7b66-188-130-157-6.eu.ngrok.io/ for example
#Value("${telegram.bot.webhook.internalUrl}")
private String internalWebServerUrl; // http://localhost:8080
#Bean
public TelegramWebhookBot telegramWebhookBot() throws TelegramApiException {
DefaultWebhook defaultWebhook = new DefaultWebhook();
defaultWebhook.setInternalUrl(internalWebServerUrl);
TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class, defaultWebhook);
WebhookBot telegramBot = new WebhookBot(name, token);
SetWebhook setWebhook = new SetWebhook();
setWebhook.setUrl(webhookUri);
botsApi.registerBot(telegramBot, setWebhook);
return telegramBot;
}
}
./ngrok http 8080
I get an error in he "import org.springframework.data cannot be
resolved" in following code
package com.steinko.reactsprinboottutorial.RestfulWebService;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface TodoRepository extends CrudRepository<Todo, Long>{
List<Todo> findByName(String Name);
}
The gradle build.gradle looks like
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
}
apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
mavenCentral()
jcenter()
mavenLocal()
// maven { url "http://dl.bintray.com/epam/reportportal" }
}
sourceCompatibility = '14'
sourceSets {
intTest {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
configurations {
intTestImplementation.extendsFrom implementation
intTestCompile.extendsFrom testCompile
intTestRuntimeOnly.extendsFrom runtimeOnly
}
dependencies {
//implementation 'com.epam.reportportal:logger-java-log4j:5.0.2'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.modelmapper:modelmapper:2.3.8'
// https://mvnrepository.com/artifact/javax.validation/validation-api
compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
implementation 'org.springframework.boot:spring-boot-starter-validation'
runtimeOnly 'org.postgresql:postgresql'
// https://mvnrepository.com/artifact/org.testcontainers/testcontainers
testCompile group: 'org.testcontainers', name: 'testcontainers', version: '1.15.0-rc1'
testCompile group: 'org.testcontainers', name: 'postgresql', version: '1.15.0-rc1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:spring-mock-mvc:4.3.1'
testImplementation 'io.rest-assured:rest-assured-common:4.3.1'
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testCompile group: 'org.modelmapper', name: 'modelmapper', version: '2.3.8'
testImplementation 'com.epam.reportportal:agent-java-junit5:5.0.0-RC-1'
intTestCompile group: 'org.testcontainers', name: 'testcontainers', version: '1.15.0-rc1'
intTestCompile group: 'org.testcontainers', name: 'postgresql', version: '1.15.0-rc1'
intTestImplementation 'org.springframework.boot:spring-boot-starter-test'
intTestImplementation 'io.rest-assured:spring-mock-mvc:4.1.2'
intTestImplementation 'com.epam.reportportal:agent-java-junit5:5.0.0-RC-1'
intTestRuntimeOnly 'org.postgresql:postgresql'
}
test {
// testLogging.showStandardStreams = true
useJUnitPlatform()
// systemProperty 'junit.jupiter.extensions.autodetection.enabled', true
}
task integrationTest(type: Test) {
description = 'Runs integration tests.'
group = 'verification'
testClassesDirs = sourceSets.intTest.output.classesDirs
classpath = sourceSets.intTest.runtimeClasspath
shouldRunAfter test
}
When I run the test for the service I get a nullpointer for repository
TodoServiceTest > shoulCreateTodo() FAILED
java.lang.NullPointerException at TodoServiceTest.java:55
TodoServiceTest > shouldDeleteTodo() FAILED
java.lang.NullPointerException at TodoServiceTest.java:48
package com.steinko.reactsprinboottutorial.RestfulWebService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class TodoServiceTest {
private static final Logger logger = LoggerFactory.getLogger(TodoServiceTest.class);
private TodoService service = new TodoService();
#Test
void ShouldExist() {
assertNotNull (service);
}
#Test
void shouldDeleteTodo() {
service.deleteTodo("stein", 1L);
}
#Test
void shoulCreateTodo() {
Date date = DateFactory.generetDate("01-01-2020 12:00:00");
TodoDto todo = new TodoDto(1,"Stein","Fix Kjakk", date,false);
service.createTodo(todo);
}
}
The service test looks like
package com.steinko.reactsprinboottutorial.RestfulWebService;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Service
public class TodoService {
private static final Logger logger = LoggerFactory.getLogger(TodoService.class);
#Autowired
private TodoRepository repository;
public List<TodoDto> getTodos(String name) {
List<Todo> todos = repository.findByName(name);
TodoConverter converter = new TodoConverter();
List<TodoDto> dtos = converter.convertToDtos(todos);
return dtos;
}
public void deleteTodo(String name, Long id) {
repository.deleteById(id);
}
public void createTodo(TodoDto dto) {
TodoConverter converter = new TodoConverter();
Todo todo = converter.convertToEntity(dto);
validateEntity(todo);
repository.save(todo);
}
private void validateEntity(Todo todo) {
List<String> errorMessage = new ArrayList<>();
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Todo>> constraintViolations = validator.validate(todo);
for (ConstraintViolation<Todo> constraintViolation : constraintViolations) {
errorMessage.add(constraintViolation.getMessage());
}
if (errorMessage.size() > 0) {
throw new ConstraintViolationException(constraintViolations);
}
}
}
How do I get access to org.springframework.data and an object at repository variabel ?
You have to annotate the test class with either #SpringBootTest or #DataJpaTest so the repository will be initialised and injected into your service. Furthermore, you have to autowire your service in the test, or the repository will not be injected in the instance created by you.
I start learning Spring and in the tutorial from which I learn the lecturer uses the method: startAndAwait, which was in the reactor.ipc.netty.http.server.HttpServer package. Now there is no method, and the package is reactor.netty.http.server.HttpServer.
I would like to learn a solution based on the latest package, therefore my question is what will be the current equivalent of the following code:
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.ipc.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer.create("localhost",8080);
server.startAndAwait(new ReactorHttpHandler(httpHandler));
}
}
I was looking for a solution, but my knowledge is so low that I can not cope alone with this problem. So far I wrote I changed the code to the place "server.startAndAwait" still can not replace this method:
package pl.javasurvival.helloServer;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer
.create()
.host("localhost")
.port(8080);
//what is a new method which is equals to startAndAwait
}
}
PS: I forgot to add that I use gradle. This is the build.gradle file:
plugins {
id 'org.springframework.boot' version '2.2.0.M4'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'pl.javasurvival'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux:2.2.0.M4'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
exclude group: 'junit', module: 'junit'
}
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
it has been a while, but I've found this question 1 hour ago and now I have solution, so it could be helpful for others.
Without importing old version of reactor.netty, you could try this (scanner is added only for waiting for action)
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import java.util.Scanner;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args) {
RouterFunction route = route(GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
var httpHandler = RouterFunctions.toHttpHandler(route);
var adapter = new ReactorHttpHandlerAdapter(httpHandler);
var server = HttpServer.create().host("localhost").port(8080).handle(adapter).bindNow();
System.out.println("press enter");
Scanner sc = new Scanner(System.in);
sc.next();
server.disposeNow();
}
}
You can use the method block, as in:
DisposableServer server =
HttpServer.create()
.bindNow();
server.onDispose()
.block();
Read more in the Reactor Netty docs.
I have a controller with the following:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.Validator;
#RestController
#RequestMapping("/")
public class MyController {
#Autowired
private Validator validator;
//..elided...
#GetMapping
public String getSomething(#Valid #RequestBody MyRequest) {
//This is null
if ( validator == null ) {
throw new Exception("is null");
}
}
}
My configuration class:
package com.app.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#EnableWebMvc
#ComponentScan("com.app")
public class ValidationConfig {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
/* //Including this doesn't help
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}*/
}
Gradle:
buildscript {
ext {
springBootVersion = "1.5.6.RELEASE"
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: "java"
apply plugin: "eclipse"
apply plugin: "org.springframework.boot"
apply plugin: "idea"
apply plugin: "jacoco"
jar {
baseName = "my-service"
version = "0.0.1-SNAPSHOT"
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
//Spring Boot
compile("org.springframework.boot:spring-boot-starter")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
//Testing
testCompile("org.hamcrest:hamcrest-all:1.3")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
No matter what I do, the validator in my controller is null!
In your controller you are expecting a javax.validation.Validator but in the config you are using org.springframework.validation.Validator