Issue
I have controller and method deleteFolder has @RequestParam:
@RestController
public class FolderController extends BaseController {
@DeleteMapping(path = Const.APIVersions.API_V1 + "/folders", params = "id")
public ResponseEntity<HttpStatus> deleteFolder(KeycloakAuthenticationToken authentication, @RequestParam Long id) throws EntityNotFoundException {
folderService.deleteFolder(id, authentication.getName());
return ResponseEntity.ok(HttpStatus.OK);
}
parent class:
public abstract class BaseController {
@ExceptionHandler({MissingServletRequestParameterException.class,
UnsatisfiedServletRequestParameterException.class, MethodArgumentTypeMismatchException.class,
IllegalArgumentException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorResponse> handleMissingServletRequestParameter(MissingServletRequestParameterException exception) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage()));
}
I want to handle exception, when required param is missing. But that exception handler don't want to catch that exception raised from deletFolder method.
Any others handlers works.
Solution
You have to create custom ConstraintValidator
and catch ConstraintViolationException
so your base controller becomes
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import javax.validation.*;
public abstract class BaseController {
@ExceptionHandler({ConstraintViolationException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorResponse> handlerFolderNotFoundException(ConstraintViolationException exception) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage()));
}
}
Validation Annotation
import javax.validation.*;
import java.lang.annotation.*;
@Constraint(validatedBy = FolderValidationConstraint.class)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateFolder {
String message() default "Error validating folder name";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator class
import lombok.extern.slf4j.*;
import javax.validation.*;
import java.io.*;
@Slf4j
public class FolderValidationConstraint implements ConstraintValidator<ValidateFolder, String> {
@Override
public boolean isValid(String path, ConstraintValidatorContext constraintValidatorContext) {
return new File("/home/ashish/Documents/test-delete/" + path).exists();
}
}
Controller
import org.springframework.validation.annotation.*;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.util.*;
@Validated
@RestController
@RequestMapping(path = "/folders")
public class FolderController extends BaseController {
@GetMapping
public Map<String, Boolean> delete(@ValidateFolder @RequestParam("name") String folderName) {
final File path = new File("/home/ashish/Documents/test-delete/" + folderName);
return Map.of("exists", path.exists());
}
}
Please make sure to add dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Answered By - silentsudo