How To Implement Restful Web Services In Java
Spring Bean Validation
Data validation is not a new topic in spider web awarding development.
We have a cursory look at information validation in the Coffee ecosystem in full general and the Jump Framework specifically. The Coffee platform has been the de facto standard for implementing data validation that is Bean Validation specification. Bean Validation specification has several versions:
- one.0 (JSR-303),
- 1.1 (JSR-349),
- ii.0 (JSR 380) – the latest version
This specification defines a set of components, interfaces, and annotations. This provides a standard way to put constraints to the parameters and return values of methods and parameters of constructors, provide API to validate objects and object graphs.
A Declarative model is used to put constraints in the form of annotations on objects and their fields. There are predefined annotations like @NotNull
, @Digits
, @Blueprint
, @Email
, @CreditCard
. In that location is an ability to create new custom constraints.
Validation can run manually or more naturally, when other specification and frameworks validate data at the correct time, for case, user input, insert or update in JPA.
Validation in Coffee Example
Let's take a look at how information technology can be done in exercise in this simple Bean Validation instance inside regular Java application.
Nosotros have an object that we want to validate with all fields annotated with constraints.
public form SimpleDto { @Min(value = 1, bulletin = "Id can't be less than 1 or bigger than 999999") @Max(999999) private int id; @Size(max = 100) private String name; @NotNull private Boolean active; @NotNull private Date createdDatetime; @Pattern(regexp = "^asc|desc$") private String order = "asc"; @ValidCategory(categoryType="simpleDto") private Cord category; … Constructor, getters and setters
Notation: @Min
, @Max
, @Size
, @NotNull
, and @Blueprint
are standard annotations, and @ValidCategory
is custom.
Now nosotros can use it in a simple Java awarding and manually validate the object.
public grade SimpleApplication { public static void master(String[] args) { final SimpleDto simpleDto = new SimpleDto(); simpleDto.setId(-1); simpleDto.setName("Test Name"); simpleDto.setCategory("simple"); simpleDto.setActive(truthful); simpleDto.setOrder("asc"); simpleDto.setCreatedDatetime(new Date()); ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); Validator validator = validatorFactory.usingContext().getValidator(); Set constrains = validator.validate(simpleDto); for (ConstraintViolation constrain : constrains) { Organization.out.println( "[" + constrain.getPropertyPath() + "][" + constrain.getMessage() + "]" ); } } }
And upshot in Console will be:
"[id] [Id tin't exist less than 1 or bigger than 999999]"
Validation Constraint and Note
Create a custom validation constraint and annotation.
@Retention(RUNTIME) @Target(FIELD) @Constraint(validatedBy = {ValidCategoryValidator.class}) public @interface ValidCategory { String categoryType(); String message() default "Category is not valid"; Course<?>[] groups() default {}; Grade<? extends Payload>[] payload() default {}; } And constraint validation implementation: public class ValidCategoryValidator implements ConstraintValidator<ValidCategory, String> { individual static last Map<String, Listing> availableCategories; static { availableCategories = new HashMap<>(); availableCategories.put("simpleDto", Arrays.asList("simple", "advanced")); } private String categoryType; @Override public void initialize(ValidCategory constraintAnnotation) { this.setCategoryType(constraintAnnotation.categoryType()); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { List categories = ValidCategoryValidator.availableCategories.get(categoryType); if (categories == cypher || categories.isEmpty()) { render simulated; } for (String category : categories) { if (category.equals(value)) { return true; } } return false; } }
In the example higher up, bachelor categories come up from a simple hash map. In real application use cases, they can be retrieved from the database or any other services.
Please annotation that constraints and validations could exist specified and performed not merely on the field level, just besides on an entire object.
When we need to validate various field dependencies, for case, kickoff appointment, it can't be after the end appointment.
The most widely used implementations of Bean Validation specifications are Hibernate Validator and Apache BVal.
Validation with Bound
The Leap framework provides several features for validation.
- Support for Edible bean Validation API versions i.0, 1.ane (JSR-303, JSR-349) was introduced in Leap Framework starting with version iii.
- Jump has its own Validator interface that is very basic and can be set in specific DataBinder instance. This could be useful for implementing validation logic without annotations.
Bean Validation with Spring
Leap Kicking provides validation started which tin can be included in the project:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-kicking-starter-validation</artifactId> </dependency>
This starter provides a version of Hibernate Validator compatible with the current Spring Boot.
Using Bean Validation, nosotros could validate a request torso, query parameters, variables within the path (due east.g. / /simpledto/{id}), or any method or constructor parameters.
Post or PUT Requests
In POST or PUT requests, for case, we pass JSON payload, Spring automatically converts it into Java object and now we want to validate resulting object. Let'due south employ SimpleDto
object from the 1st example:
@RestController @RequestMapping("/simpledto") public class SimpleDtoController { @Autowired private SimpleDtoService simpleDtoService; @RequestMapping(path = "", method = RequestMethod.Mail service, produces = "application/json") public SimpleDto createSimpleDto( @Valid @RequestBody SimpleDto simpleDto) { SimpleDto result = simpleDtoService.save(simpleDto); render effect; } }
We just added @Valid
annotation to the SimpleDto
parameter annotated with @RequestBody
. This will tell Spring to process validation before making an bodily method phone call. In example validation fails, Spring volition throw a MethodArgument NotValidException
which, past default, will return a 400 (Bad Asking) response.
Validating Path Variables
Validating Path Variables works a fiddling differently. The problem is that now we take to add constraint annotations straight to method parameters instead of inside of objects.
To brand this work in that location are two possible options:
Option 1: @Validated Annotation
Add together @Validated
annotation to the controller at the grade level to evaluate constraint annotations on method parameters.
Option 2: Path Variable
Apply an object that represents the path variable as seen in the case beneath:
@RestController @RequestMapping("/simpledto") public form SimpleDtoController { @Autowired private SimpleDtoService simpleDtoService; @RequestMapping(path = "/{simpleDtoId}", method = RequestMethod.Get, produces = "application/json") public SimpleDto getSimpleDto( @Valid SimpleDtoIdParam simpleDtoIdParam) { SimpleDto result = simpleDtoService.findById(simpleDtoIdParam.getSimpleDtoId()); if (consequence == null) { throw new NotFoundException(); } render result; } }
In this instance, we accept SimpleDtoIdParam
grade that contains the simpleDtoId
field which volition be validated against a standard or custom Bean constraint note. Path Variable name (/{simpleDtoId}) should be the same as the field name (so Spring volition exist able to observe the setter for this field).
private static final long serialVersionUID = -8165488655725668928L; @Min(value = ane) @Max(999999) private int simpleDtoId; public int getSimpleDtoId() { return simpleDtoId; } public void setSimpleDtoId(int simpleDtoId) { this.simpleDtoId = simpleDtoId; } }
In dissimilarity to Request Trunk validation, Path Variable validation throws ConstraintViolationException
instead of MethodArgumentNotValidException
. Therefore, we will demand to create a custom exception handler.
The Java Jump framework also allows validating parameters on a service level with @Validated
annotation (grade level) and @Valid
(parameter level).
Considering Spring JPA is using Hibernate underneath, it supports Bean Validation for entity classes as well. Please note that it's probably not a good idea in many cases rely on this level of validation since it means that all logic before was dealing with invalid objects.
Spring Validation Interface
Jump defines its ain interface for validation Validator (org.springframework.validation.Validator). It tin can be fix for a specific DataBinder instance and implement validation without annotations (non-declarative approach).
To implement this approach we would need to:
- Implement the Validator Interface
- Add Validator
Implement Validator Interface
Implement the Validator interface, for example lets piece of work with our SimpleDto
form:
@Component public class SpringSimpleDtoValidator implements Validator { @Override public boolean supports(Class<?> clazz) { render SimpleDto.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { if (errors.getErrorCount() == 0) { SimpleDto param = (SimpleDto) target; Appointment now = new Date(); if (param.getCreatedDatetime() == nothing) { errors.reject("100", "Create Date Time tin't exist null"); } else if (at present.before(param.getCreatedDatetime())) { errors.decline("101", "Create Engagement Time tin can't exist subsequently current date time"); } } } }
Check here if the created Datetime
timestamp is in the future.
Add Validator
Add together Validator implementation to DataBinder
:
@RestController @RequestMapping("/simpledto") public course SimpleDtoController { @Autowired individual SimpleDtoService simpleDtoService; @Autowired private SpringSimpleDtoValidator springSimpleDtoValidator; @InitBinder("simpleDto") public void initMerchantOnlyBinder(WebDataBinder binder) { binder.addValidators(springSimpleDtoValidator); } @RequestMapping(path = "", method = RequestMethod.POST, produces = "application/json") public SimpleDto createSimpleDto( @Valid @RequestBody SimpleDto simpleDto) { SimpleDto result = simpleDtoService.salve(simpleDto); render effect; } }
Now we have SimpleDto
validated using constraint annotations and our custom Spring Validation implementation.
Conclusion
This article touched on Coffee Spring Validation with a detail focus on Java Edible bean Validation specification. This includes its implementation and how it'due south supported in the Spring Framework Validation Interface.
For farther reference, here is the GitHub repository with code examples presented in this article.
Was this article helpful?
Aye No
How To Implement Restful Web Services In Java,
Source: https://phoenixnap.com/kb/spring-boot-validation-for-rest-services
Posted by: owensrigand73.blogspot.com
0 Response to "How To Implement Restful Web Services In Java"
Post a Comment