I am trying to implement custom annotation in spring as follows:-
Test annotation is as follows
#Documented
#Target( { ElementType.METHOD, ElementType.FIELD })
#Constraint(validatedBy=CheckUser.class)
#Retention(RetentionPolicy.RUNTIME)
public #interface Test {
String user();
}
And for validation I have written CheckUser class as follows::-
private String xyz;
#Override
public void initialize(Test user) {
xyz=user.toString();
}
#Override
public boolean isValid(Principal principal, ConstraintValidatorContext context) {
if(principal.getName().equalsIgnoreCase(xyz))
return true;
else
return false;
}
But its not working. Can some one tell me what is wrong here??
In security as well as application context I have written
<Secured:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled"/>
You need to include message, groups, and payload so it plays nicely with regards to the JSR-303 spec: http://beanvalidation.org/1.0/spec/#constraintsdefinitionimplementation-constraintdefinition-properties
#Documented
#Target( { ElementType.METHOD, ElementType.FIELD })
#Constraint(validatedBy=CheckUser.class)
#Retention(RetentionPolicy.RUNTIME)
public #interface Test {
String user();
String message() default "test failed"
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Related
The following code yields null on the teamResource auto-wired object inside isValid() function:
#Component //I am not sure it is required he
public class TeamIdValidator implements ConstraintValidator<TeamIdConstraint, Integer> {
#Autowired private TeamResource teamResource;
public TeamIdValidator() {
}
#Override
public void initialize(TeamIdConstraint teamIdConstraint) {
// this.teamIdConstraint = teamIdConstraint;
}
#Override
public boolean isValid(Integer teamId, ConstraintValidatorContext cxt) {
int numOfAvailableTeams = teamResource.retrieveAllTeams().size(); //teamResource is null :(
return teamId < 0 || teamId >= numOfAvailableTeams;
}
}
TeamResource class:
#RestController
#CrossOrigin
public class TeamResource {
#Autowired private TeamRepository teamRepository;
public TeamResource() {
}
...
//mapping methods
}
And if it relevant...
#Documented
#Constraint(validatedBy = TeamIdValidator.class)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface TeamIdConstraint {
String message() default "Invalid team id!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Why on earth teamResource is null?
It is not being explicitly initialized with new anywhere else.
Already mentioned in the comments but declare a a bean like this
#Configuration
public class ValidationConfig{
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator);
return methodValidationPostProcessor;
}
}
Remove all the #autowired, prefer constructor injection. (check the internet why).
And then, it makes no sense to inject a RestContoller to validator.
I am using JSR 303 for validating my request object of rest controller. Validation is working fine but i am not getting the response. below is the code am i missing something ?
Pojo class:
#ValInfo(message ="empty filed", groups=ExtendedValidation.class)
public class Request {
Validator classes:
#Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = { ValInfoValidator.class })
#Documented
public #interface ValInfo {
String message() default "{Client information invalid}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class ValInfoValidator implements ConstraintValidator<ValInfo, TvxOnlineRequest> {
#Override
public void initialize(ValInfo arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean isValid(TvxOnlineRequest arg0, ConstraintValidatorContext arg1) {
// TODO Auto-generated method stub
return false;
}
hi I have a problem while Implementing custom validation using ConstraintValidator.
I am implementing some bean validations using JSR303 and constraint validator and upto now I have following implementation as
#ProductId// this is the problem
#NotEmpty(message = "{Domain.NotEmpty.productid}")
protected String productId;
#Pattern(regexp = "[A-Za-z]+", message = "{Domain.Pattern.firstName}")
....
#ProductId
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
#Documented
#Constraint(validatedBy = ProductIdValidator.class)
public #interface ProductId {
String message() default "{ProductId.validaton.Error}";
Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}
ProductIdValidator
public class ProductIdValidator implements ConstraintValidator<ProductId, String> {
#Autowired
private RepositiryObject repo;
#Override
public void initialize(ProductId productId) {
}
#Override
public boolean isValid(String string, ConstraintValidatorContext constraintValidatorContext) {
Domain domain;
try {
domain = repo.getProductById(string);
} catch (ProdctNotFoundException ex) {
return true;
}
if (domain != null) {
return false;
}
return true;
}
}
StackTrace
Request processing failed; nested exception is javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.] with root cause
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at com.model.domain.controller.repo.RepositiryObject.getProductById(RepositiryObject.java:45)
at com.java.spring.custom.validation.annotations.constraints.ProductIdValidator.isValid(ProductIdValidator.java:28)
at com.java.spring.custom.validation.annotations.constraints.ProductIdValidator.isValid(ProductIdValidator.java:1)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:448)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:127)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:87)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:617)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:580)
dispatcherservlet
<mvc:annotation-driven validator="validator" />
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource" />
</bean>
......
EditSince exception says that no such element is present but when I ran test its working fine as
public RepositiryObject() {
domainList = new ArrayList<>();
Domain domain = new Domain();
domain.setProductId("P1234");
domainList.add(domain);
}
#Test
public void checkIfProductExists() {
Assert.assertEquals("P1234", domainList.stream().filter(product -> product.getProductId().equals("P1234"))
.map(Domain::getProductId).findAny().get());
}
Now the problem is when I remove that #ProductId it works fine not sure what I am missing here
I've created a custom constraint validator that works on a list of objects. Unfortunately it doesn't seem to be getting invoked, it worked when I had a wrapper class containing the list with the annotation on the list.
This is the code that worked fine
public class wrapper {
#ValidMyObjectList
List<MyObject> myObjects;
...
}
But now I've got rid of the wrapper class and added the annotation to the parameter in the controller method.
Here's the controller
#RequestMapping(value = "", method = RequestMethod.POST)
public List<MyObject> stopCheque(
#ValidMyObjectList #RequestBody final List<MyObject> myObjects,
final HttpServletResponse httpServletResponse) {
....
}
Here's the constraint annotation
#Constraint(validatedBy = MyObjectListValidator.class)
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface MyObjectList {
Class<?>[] groups() default {};
String message() default "";
Class<? extends Payload>[] payload() default {};
}
And part of the validator itself
public class MyObjectListValidator implements
ConstraintValidator<MyObjectList, List<MyObject>> {
#Override
public void initialize(final MyObjectList myObjectList) {
}
#Override
public boolean isValid(final List<MyObjectList> myObjectLists, final ConstraintValidatorContext cxt) {
...
}
Would greatly appreciate any help. Thanks
Add to your Spring config class:
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
and add #Validated to controller class.
I have controller with method:
void save(#Validated(BookingForm.ValidationSave.class) #RequestBody BookingForm form, Errors result) {...}
and BookingForm with a field and my custom validator:
public class BookingForm {
public interface ValidationSave {}
public interface ValidationEstimate {}
....
#Future
private LocalDateTime when;
....
}
Future.java
#Target({ ElementType.FIELD })
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = FutureValidator.class)
#Documented
public #interface Future {
String message() default "{javax.validation.constraints.Future.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I've expected that validator will valid my 'when' field but it does not.
When I removed the group from #Validated it works. Any ideas?
Works fine with #NotNull and others javax validators.
Updated:
FutureValidator.java
public class FutureValidator implements ConstraintValidator<Future, Temporal> {
#Override
public void initialize(Future constraintAnnotation) {
}
#Override
public boolean isValid(Temporal value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
LocalDate ld = LocalDate.from(value);
return ld.isAfter(LocalDate.now());
}
}