Custom annotation, as defined https://dzone.com/articles/bean-validation-and-jsr-303
Can we use #Capitalized annotation in controller?
e.g.
#RestController
public class Abc {
#RequestMapping(value="/abc", method=RequestMethod.POST)
public String abc(#Capitalized #RequestParam(value="abc") String abc) {
}
}
I used in this way, but it is not working. Any idea why it is not working?
Thanks,
Add Parameter ElementType in annotation target, then it will work.
E.g.:
#Target(ElementType.PARAMETER)
Assuming that #Capitalized is:
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = CapitalizedValidator.class)
#Documented
public #interface Capitalized {
String message() default "should be capital";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
and you have a constraint validation impl as:
public class CapitalizedValidator implements ConstraintValidator<Capitalized, String> {
private String message;
#Override
public void initialize(Capitalized constraintAnnotation) {
message = constraintAnnotation.message();
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
String inUpperCase = value.toUpperCase();
if (inUpperCase.equals(value)) {
return true;
}
context.buildConstraintViolationWithTemplate(message);
return false;
}
}
Then try this with you're controller:
#Validated
#RestController
public class SampleController {
#RequestMapping(method = RequestMethod.POST)
public String post(#Capitalized #RequestParam("content") String content) {
return content;
}
}
After including below code in Application.java, Its working fine.
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
Related
I do have simple controller which accept String as RequestBody
#RequestMapping(value = "/test", method = RequestMethod.POST)
public ResponseEntity doSmth(#RequestBody #ValidTest String val) {
//do something
return ResponseEntity
.status(HttpStatus.OK)
.body("saved");
}
But for some reason val param not being validated with TestConstraintValidator.class
#Documented
#Constraint(validatedBy = TestConstraintValidator.class)
#Target({PARAMETER})
#Retention(RUNTIME)
public #interface ValidTest{
String message() default "Invalid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Is there even option to validate this? Or do I need to wrap this String withing custom class. And validate it there?
public class TestConstraintValidator implements ConstraintValidator<ValidTest, String> {
#Override
public void initialize(ValidTest constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
#Override
public boolean isValid(String val, ConstraintValidatorContext constraintValidatorContext) {
return false;
}
}
Make sure the controller class is marked as #Validated.
There is a controller accepting code as a path variable
#RestController
#RequestMapping(value = "/api/currency")
#Validated
public class CurrencyController {
#GetMapping("/gif/{code}")
public ResponseEntity<Map> getChangeGif(#PathVariable #Code String code){
// some implementation
return null;
}
}
I want to use my own annotation to validate code as I want
#Target( { FIELD, PARAMETER })
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = CodeValidator.class)
public #interface Code {
public String message() default "error message";
public Class<?>[] groups() default {};
public Class<? extends Payload>[] payload() default {};
}
And here is the validator
public class CodeValidator implements ConstraintValidator<Code, String> {
#Override
public void initialize(Code constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
#Override
public boolean isValid(String code, ConstraintValidatorContext context) {
// validator implementation
return false;
}
}
For some reason when requests come, validation just skipps, and controller continue working without it
I created my own Annotation to validate my REST parameter like this:
#PostMapping("/users")
#ResponseStatus(HttpStatus.CREATED)
public User createUser(#UserConstraint("CREATE_MODE") #RequestBody User user)
{ //code }
I got everything working where my ConstraintValidator is called to validate the User input, but I can't figure out how to get the parameter of my own annotation. I want to read the value CREATE_MODE.
#Constraint(validatedBy = UserValidator.class)
#Target(ElementType.PARAMETER )
#Retention(RetentionPolicy.RUNTIME)
public #interface UserConstraint {
String message() default "";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
public String value();
}
How to access??
public class UserValidator implements ConstraintValidator<UserConstraint, User> {
#Override
public boolean isValid(User user,
ConstraintValidatorContext context) {
???
}
#Override
public void initialize(UserConstraint annotation) {
// initialization, probably not needed
mode = annotation.value();
}
I have created a custom validator to validate the String passed to the function in converter. However, the custom validator is not being called. Am I missing something?
OperationParameter.java
#Documented
#Constraint(validatedBy = OperationParameterValidation.class)
#Target( { ElementType.PARAMETER
})
#Retention(RetentionPolicy.RUNTIME)
public #interface OperationParameter {
String message() default "Operation Parameter Invalid";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
OperationParameterValidation.java
public class OperationParameterValidation implements ConstraintValidator<OperationParameter, String> {
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("Validator called");
// validation process
// return true / false;
}
}
converter.java
#Component
public class StringToOperation implements Converter<String, Operation> {
#Override
public Operation convert(#Valid #OperationParameter String source) {
// Even I pass wrong String this function is executed successfully, and no print from validator
}
}
Service.java
public class Service {
#Autowired
ConversionService conversionService;
public void action() {
String action = "";
Operation addInsertOperation = conversionService.convert(action, Operation.class);
}
}
Set #SupportedValidationTarget(ValidationTarget.PARAMETERS) on validator class
I'm using Spring version 4.1.6.RELEASE. I have the following custom ConstraintValidator.
public class CountryCodeValidator implements ConstraintValidator<CountryCode, String> {
private List<String> allowedCountries;
#Autowired
public void setAllowedCountries(#Value("${allowed.countries}")String countries) {
allowedCountries = Arrays.asList(countries.split(","));
}
#Override
public void initialize(CountryCode constraintAnnotation) { }
#Override
public boolean isValid(String countryCode, ConstraintValidatorContext ctx) {
return null != countryCode && allowedCountries.contains(countryCode.toUpperCase());
}
}
and I have the following annotation
#Documented
#Constraint(validatedBy = CountryCodeValidator.class)
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface CountryCode {
String message() default "{CountryCode}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I'm using this in a request object like the following
#CountryCode(message = MessageKeys.COUNTRY_CODE_INVALID)
private String countryCode;
When I run the application, everything is working as expected. However in the unit test for the controller it is failing.
My unit test code is like the following
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/test-context.xml")
public class ControllerTest {
#InjectMocks
private Controller controller;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testEndpoint() {
Request request = new Request();
RestAssuredMockMvc.given().standaloneSetup(controller).contentType(MediaType.APPLICATION_JSON_VALUE).body(request)
.post("/endpoint").then().statusCode(HttpStatus.OK.value());
}
}
When I run the code I could not get #Value("${allowed.countries}"), therefore I'm receiving a null pointer exception in the isValid method.
What am I missing?
Thanks in advance