the model is generated by some tools. Particular fields are annotated by for instance @NotNull annotation. I cannot modify generated classes. I need to do additonal validation of generated classes like check that value of the string field does't contain empty string and then throw ConstraintViolationException. Currently I iterate over the class to find field type of String and then in case of empty string I need to implement my own ConstraintViolation interface which is deadly hard. So it looks like that:
Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
Set< ConstraintViolation< E > > validationErrors = validator.validate(aEntity);
Field[] fields = aEntity.getClass().getDeclaredFields();
for (Field f : fields) {
Class<?> type = f.getType();
if (type == String.class) {
try {
String v = (String) f.get(aEntity);
// check that value is not an empty string
if (v == null || !v.trim().isEmpty()) {
validationErrors.add(new ConstraintViolation<E>() {
@Override
public String getMessage() {
return null;
}
@Override
public String getMessageTemplate() {
return null;
}
@Override
public E getRootBean() {
return null;
}
@Override
public Class<E> getRootBeanClass() {
return null;
}
@Override
public Object getLeafBean() {
return null;
}
@Override
public Object[] getExecutableParameters() {
return new Object[0];
}
@Override
public Object getExecutableReturnValue() {
return null;
}
@Override
public Path getPropertyPath() {
return null;
}
@Override
public Object getInvalidValue() {
return null;
}
@Override
public ConstraintDescriptor<?> getConstraintDescriptor() {
return null;
}
@Override
public <U> U unwrap(Class<U> type) {
return null;
}
});
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Is it possible to make this easier?
For cases when it is not possible to edit the classes to add validation annotations to it there are two options:
To use this approach you'd need to add a META-INF/validation.xml
and then inside of it you can define/redefine your constraints:
<?xml version="1.0" encoding="UTF-8"?>
<constraint-mappings
xmlns="https://jakarta.ee/xml/ns/validation/mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://jakarta.ee/xml/ns/validation/mapping
https://jakarta.ee/xml/ns/validation/validation-mapping-3.0.xsd"
version="3.0">
<!-- note that you can use ignore-annotations
to either ignore any annotation constraints
or include them, depending on your needs -->
<bean class="com.acme.common.model.SomeType" ignore-annotations="false">
<field name="someField">
<constraint annotation="jakarta.validation.constraints.NotBlank"/>
[...]
</field>
[...]
</bean>
</constraint-mappings>
for more details you should check this section of the specification.
Alternatively, Hibernate Validator provides a way to add constraints programmatically:
HibernateValidatorConfiguration configuration = Validation
.byProvider( HibernateValidator.class )
.configure();
ConstraintMapping constraintMapping = configuration.createConstraintMapping();
constraintMapping
.type( Car.class )
.field( "manufacturer" )
.constraint( new NotNullDef() )
.field( "licensePlate" )
.ignoreAnnotations( true )
.constraint( new NotNullDef() )
.constraint( new SizeDef().min( 2 ).max( 14 ) )
.type( RentalCar.class )
.getter( "rentalStation" )
.constraint( new NotNullDef() );
Validator validator = configuration.addMapping( constraintMapping )
.buildValidatorFactory()
.getValidator();
For more details, check this section of the Hibernate Validator documentation.
If you do not know which fields will need not empty/blank constraint being applied you can try to iterate through the fields using the reflection and then based on that information define the constraints via programmatic API. once constraints are added to the validator you should be able to just use Validator#validate(..)