Spring Data Rest Validators introduction (#650)
* - created packages for each logical part of application - created validator for WebsiteUser rest API - created ValidatorEventRegister class which fixes known bug for not detecting generated events - created custom Exception Handler which creates better response messages * Code formatting * formated pom.xml replaced for loops with streams fixed bug while getting all beans * removed unnecessary code changed repository type * - added test for Spring Data REST APIs - changed bad request return code - formated code
This commit is contained in:
parent
fa059546e5
commit
38b419d8e9
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
|
@ -15,7 +15,7 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.3.3.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
<relativePath /> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||
|
||||
@SpringBootApplication
|
||||
public class SpringDataRestApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringDataRestApplication.class, args);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringDataRestApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
|
||||
public interface UserRepository extends PagingAndSortingRepository<WebsiteUser, Long> {
|
||||
List<WebsiteUser> findByName(@Param("name") String name);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
@Configuration
|
||||
public class ValidatorEventRegister implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
ValidatingRepositoryEventListener validatingRepositoryEventListener;
|
||||
|
||||
@Autowired
|
||||
private Map<String, Validator> validators;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
List<String> events = Arrays.asList("beforeCreate", "afterCreate", "beforeSave", "afterSave", "beforeLinkSave", "afterLinkSave", "beforeDelete", "afterDelete");
|
||||
|
||||
for (Map.Entry<String, Validator> entry : validators.entrySet()) {
|
||||
events.stream().filter(p -> entry.getKey().startsWith(p)).findFirst().ifPresent(p -> validatingRepositoryEventListener.addValidator(p, entry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.exception.handlers;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.rest.core.RepositoryConstraintViolationException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ExceptionHandler({ RepositoryConstraintViolationException.class })
|
||||
public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) {
|
||||
RepositoryConstraintViolationException nevEx = (RepositoryConstraintViolationException) ex;
|
||||
|
||||
String errors = nevEx.getErrors().getAllErrors().stream().map(p -> p.toString()).collect(Collectors.joining("\n"));
|
||||
return new ResponseEntity<Object>(errors, new HttpHeaders(), HttpStatus.NOT_ACCEPTABLE);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung;
|
||||
package com.baeldung.models;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.repositories;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
import com.baeldung.models.WebsiteUser;
|
||||
|
||||
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
|
||||
public interface UserRepository extends CrudRepository<WebsiteUser, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.validators;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import com.baeldung.models.WebsiteUser;
|
||||
|
||||
@Component("beforeCreateWebsiteUserValidator")
|
||||
public class WebsiteUserValidator implements Validator {
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return WebsiteUser.class.equals(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object obj, Errors errors) {
|
||||
|
||||
WebsiteUser user = (WebsiteUser) obj;
|
||||
if (checkInputString(user.getName())) {
|
||||
errors.rejectValue("name", "name.empty");
|
||||
}
|
||||
|
||||
if (checkInputString(user.getEmail())) {
|
||||
errors.rejectValue("email", "email.empty");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkInputString(String input) {
|
||||
return (input == null || input.trim().length() == 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.baeldung.validator;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.baeldung.SpringDataRestApplication;
|
||||
import com.baeldung.models.WebsiteUser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = SpringDataRestApplication.class)
|
||||
@WebAppConfiguration
|
||||
public class SpringDataRestValidatorTest {
|
||||
public static final String URL = "http://localhost";
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
protected WebApplicationContext wac;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mockMvc = webAppContextSetup(wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStartingApplication_thenCorrectStatusCode() throws Exception {
|
||||
mockMvc.perform(get("/users")).andExpect(status().is2xxSuccessful());
|
||||
};
|
||||
|
||||
@Test
|
||||
public void whenAddingNewCorrectUser_thenCorrectStatusCodeAndResponse() throws Exception {
|
||||
WebsiteUser user = new WebsiteUser();
|
||||
user.setEmail("john.doe@john.com");
|
||||
user.setName("John Doe");
|
||||
|
||||
mockMvc.perform(post("/users", user).contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(redirectedUrl("http://localhost/users/1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingNewUserWithoutName_thenErrorStatusCodeAndResponse() throws Exception {
|
||||
WebsiteUser user = new WebsiteUser();
|
||||
user.setEmail("john.doe@john.com");
|
||||
|
||||
mockMvc.perform(post("/users", user).contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
|
||||
.andExpect(status().isNotAcceptable())
|
||||
.andExpect(redirectedUrl(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingNewUserWithEmptyName_thenErrorStatusCodeAndResponse() throws Exception {
|
||||
WebsiteUser user = new WebsiteUser();
|
||||
user.setEmail("john.doe@john.com");
|
||||
user.setName("");
|
||||
mockMvc.perform(post("/users", user).contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
|
||||
.andExpect(status().isNotAcceptable())
|
||||
.andExpect(redirectedUrl(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingNewUserWithoutEmail_thenErrorStatusCodeAndResponse() throws Exception {
|
||||
WebsiteUser user = new WebsiteUser();
|
||||
user.setName("John Doe");
|
||||
|
||||
mockMvc.perform(post("/users", user).contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
|
||||
.andExpect(status().isNotAcceptable())
|
||||
.andExpect(redirectedUrl(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingNewUserWithEmptyEmail_thenErrorStatusCodeAndResponse() throws Exception {
|
||||
WebsiteUser user = new WebsiteUser();
|
||||
user.setName("John Doe");
|
||||
user.setEmail("");
|
||||
mockMvc.perform(post("/users", user).contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(user)))
|
||||
.andExpect(status().isNotAcceptable())
|
||||
.andExpect(redirectedUrl(null));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue