BAEL-3005 | Validating List objects in Spring

This commit is contained in:
Pallavi Priyadarshani 2019-07-23 21:53:15 +05:30 committed by GitHub
parent a057974b11
commit a178f09ef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 325 additions and 0 deletions

View File

@ -18,6 +18,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies> </dependencies>
<properties> <properties>

View File

@ -0,0 +1,17 @@
package com.baeldung.validation.listvalidation;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = "com.baeldung.validation.listvalidation")
@Configuration
@SpringBootApplication
public class SpringListValidationApplication {
public static void main(String[] args) {
SpringApplication.run(SpringListValidationApplication.class, args);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.validation.listvalidation.constraint;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.validation.Constraint;
import javax.validation.Payload;
@Constraint(validatedBy = CustomConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomConstraint {
String message() default "Invalid movie name.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,17 @@
package com.baeldung.validation.listvalidation.constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CustomConstraintValidator implements ConstraintValidator<CustomConstraint, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty()) {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,54 @@
package com.baeldung.validation.listvalidation.controller;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import com.baeldung.validation.listvalidation.model.Movie;
import com.baeldung.validation.listvalidation.repository.MovieRepository;
@Validated
@RestController
@RequestMapping("/movie")
public class MovieController {
private final Logger LOGGER = LoggerFactory.getLogger(MovieController.class);
@Autowired
private MovieRepository movieRepository;
@RequestMapping(method = RequestMethod.POST)
public void add(@RequestBody @Valid Movie movie, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
StringBuilder builder = new StringBuilder();
bindingResult.getAllErrors()
.forEach(error -> builder.append(" " + error.getDefaultMessage()));
LOGGER.error(builder.toString());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, bindingResult.toString());
}
movieRepository.add(movie);
}
@RequestMapping(value = "/batch", method = RequestMethod.POST)
public void addAll(@RequestBody List<@Valid Movie> movie) {
movieRepository.addAll(movie);
}
@RequestMapping(method = RequestMethod.GET, value = "/{name}")
public Movie get(@PathVariable String name) throws Exception {
return movieRepository.get(name);
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.validation.listvalidation.exception;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ConstraintViolationExceptionHandler {
private final Logger LOGGER = LoggerFactory.getLogger(ConstraintViolationExceptionHandler.class);
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<String> handle(ConstraintViolationException constraintViolationException) {
Set<ConstraintViolation<?>> violations = constraintViolationException.getConstraintViolations();
StringBuilder builder = new StringBuilder();
for (ConstraintViolation<?> violation : violations) {
builder.append(violation.getMessage());
}
LOGGER.error(builder.toString());
return new ResponseEntity<String>(builder.toString(), HttpStatus.BAD_REQUEST);
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.validation.listvalidation.model;
import java.util.UUID;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class Actor {
private String id;
private String name;
public Actor(String name) {
this.id = UUID.randomUUID()
.toString();
this.name = name;
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.validation.listvalidation.model;
import java.util.List;
import java.util.UUID;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.baeldung.validation.listvalidation.constraint.CustomConstraint;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class Movie {
private String id;
@CustomConstraint
private String name;
@Size(min = 2, message = "Atleast 2 genres should be provided.")
private List<String> genres;
@NotNull(message = "Actor list cannot be null.")
@NotEmpty(message = "Actor list cannot be empty.")
private List<Actor> actors;
public Movie(String name, List<String> genres, List<Actor> actors) {
this.id = UUID.randomUUID()
.toString();
this.name = name;
this.genres = genres;
this.actors = actors;
}
}

View File

@ -0,0 +1,57 @@
package com.baeldung.validation.listvalidation.repository;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import com.baeldung.validation.listvalidation.model.Actor;
import com.baeldung.validation.listvalidation.model.Movie;
@Repository
public class MovieRepository {
private final Logger LOGGER = LoggerFactory.getLogger(MovieRepository.class);
static List<Movie> moviesData;
static {
moviesData = new ArrayList<>();
Actor a1 = new Actor("Actor1");
Movie m1 = new Movie("MovieABC", Arrays.asList("Drama"), Arrays.asList(a1));
moviesData.add(m1);
Movie m2 = new Movie("MovieDEF", Arrays.asList("Drama"), Arrays.asList(a1));
moviesData.add(m2);
}
public void add(Movie movie) {
if (get(movie.getName()) == null) {
moviesData.add(movie);
LOGGER.info("Added new movie.");
}
}
public Movie get(String name) {
Movie movie = null;
for (Movie m : moviesData) {
if (name.equalsIgnoreCase(m.getName())) {
movie = m;
LOGGER.info("Found movie with name " + name + ":" + movie);
}
}
return movie;
}
public void addAll(List<Movie> movies) {
for (Movie movie : movies) {
add(movie);
}
}
}

View File

@ -0,0 +1,65 @@
package com.baeldung.validation.listvalidation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import com.baeldung.validation.listvalidation.model.Actor;
import com.baeldung.validation.listvalidation.model.Movie;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringListValidationApplication.class)
@AutoConfigureMockMvc
public class MovieControllerIntegrationTest {
@Autowired
private MockMvc mvc;
ObjectMapper objectMapper = new ObjectMapper();
@Test
public void given1Genre_whenAddingMovie_thenThrowBadRequest() throws Exception {
Actor actor = new Actor("Actor1");
Movie movie = new Movie("Movie1", Arrays.asList("Drama"), Arrays.asList(actor));
mvc.perform(MockMvcRequestBuilders.post("/movie")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(movie)))
.andExpect(MockMvcResultMatchers.status()
.isBadRequest());
}
@Test
public void givenWithoutActor_whenAddingMovieList_thenThrowBadRequest() throws Exception {
List<Actor> actors = new ArrayList<>();
Movie movie = new Movie("Movie2", Arrays.asList("Action", "Thriller"), actors);
mvc.perform(MockMvcRequestBuilders.post("/movie/batch")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(Arrays.asList(movie))))
.andExpect(MockMvcResultMatchers.status()
.isBadRequest());
}
@Test
public void givenEmptyMovieName_whenAddingMovie_thenThrowBadRequest() throws Exception {
Actor actor = new Actor("Actor1");
Movie movie = new Movie("", Arrays.asList("Drama", "History"), Arrays.asList(actor));
mvc.perform(MockMvcRequestBuilders.post("/movie")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(movie)))
.andExpect(MockMvcResultMatchers.status()
.isBadRequest());
}
}