I am writing a library which is used for validating some specific objects.
I implemented it like strategy pattern.
What is the best pattern for implementing a validation library ?
Some of my code is shown below.
//INTERFACE
public interface IValidator {
public boolean validate(Object o) throws ValidationException;
}
//VALIDATOR OBJECT
public class Validator {
private IValidator validator;
public Validator(IValidator validator)
{
this.validator=validator;
}
public boolean validate(Object o) throws ValidationException
{
return this.validator.validate(o);
}
}
//EMAIL VALIDATOR
public class EmailValidator implements IValidator{
#Override
public boolean validate(Object o) throws ValidationException {
//VALIDATE E MAIL HERE
return false;
}
}
//TEST RUN
Validator validator = new Validator(new EmailValidator());
validator.validate("some email");
I guess the answer to this question is mainly subjective so I can only give my own opinion:
I myself use the strategy pattern as well for such tasks because that is what it is meant for. You use a specific validation strategy depending on the input of the function so the strategy pattern is alright, I think.
Read the first part of the Wiki article about the strategy pattern Strategy Pattern. Their main example is also about validation.
I would enhance your code as below:
//INTERFACE
public interface IValidator<T> {
void validate(T arg) throws ValidationException;
}
//EMAIL VALIDATOR
public class EmailValidator implements IValidator<Email email>{
#Override
public void validate(Email email) throws ValidationException {
//VALIDATE E MAIL HERE, throw exception, if needed
}
}
// Usage
EmailValidator validator = new EmailValidator();
validator.validate(); // Catch ValidatorException here to transform into business exception and appropriate error handling
Few points:
Here java Type Eraser can help implement IValidator interface with any custom implementation.
Validation logic is outside POJO, POJO is pure POJO :)
Related
I have a custom validator class that implements Validator, like this:
public class MyCustomValidator implements Validator
I want to be able to call its validate() method from a Service.
This is how this method looks:
#Override
public void validate(Object target, Errors errors) {
// validation goes here
MyClass request = (MyClass) target;
if (request.getId() == null) {
errors.reject("content.id", "Id is missing";
}
}
I don't want to have this validator in my endpoint, because I need to fetch the object to be validated from the database and then call the validation on it, so I need to do it from my service.
Can you please guide me on how to achieve this?
Use validation annotations in class but don't use #Valid on request body, then spring won't validate your class.
public class MyClass{
#NotNull
private Integer id;
#NotBlank
private String data;
}
Autowired Validator first
#Autowired
private final Validator validator;
Then for class validate using the validator conditionally when needed.
if(isValidate) {
Set<ConstraintViolation<MyClass>> violations = validator.validate(myClassObj);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(new HashSet<ConstraintViolation<?>>(violations));
}
}
The Validator interface is, as far as i understand it, called as soon as a matching object (determined by the public boolean Validator.supports(Class clazz) method).
However, your goal seems to be to validate an object of MyClass only at a specific time, coming from your persistence layer to your service layer.
There are multiple ways to achieve this.
The first and most obvious one is to not extend any classes, but to use a custom component with some notion of a validation function:
#Component
public class CustomValidator{
public void validate(MyClass target) throws ValidationException {
// validation goes here
if (target.getId() == null) {
throw new ValidationException("Id is missing");
}
}
}
And inject/autowire it into your service object:
#Component
public class MyClassService{
// will be injected in first instance of this component
#Autowired
private CustomValidator validator
public MyClass get(MyClass target) {
try {
validator.validate(target);
return dao.retrieve(target);
} catch (ValidationException) {
// handle validation error
} catch (DataAccessException) {
// handle dao exception
}
}
}
This has the benefit that you yourself can control the validation, and error handling.
The negative side is the relatively high boilerplate.
However, if you want different Validators for different CRUD-Operations (or Service Methods), you may be interested in the Spring Validation Groups Feature.
First, you create a simple marker interface for each Operation you want to differ:
interface OnCreate {};
interface OnUpdate {};
Then, all you need to do is use the marker interfaces in the fields of your entity class,
using the Bean Validation Annotations:
public class MyClass{
#Null(groups = OnCreate.class)
#NotNull(groups = OnUpdate.class)
String id;
}
In order to use those groups in your Service Class, you will have to use the #Validated annotation.
#Validated
#Service
public class MyService {
#Validated(OnCreate.class)
void validateForCreate(#Valid InputWithGroups input){
// do something
}
#Validated(OnUpdate.class)
void validateForUpdate(#Valid InputWithGroups input){
// do something
}
}
Note that #Validated is applied to the service class as well as the methods. You can also set the group for the whole service, if you plan on using multiple services.
I for once mostly use the built-in Jakarta Bean Validation annotations in combination with marker interfaces, because of their ease of use and almost no boilerplate, while staying somewhat flexible and adjustable.
You could inject Validator and call validate
#Autowired
Validator validator;
And then call validate:
Set<ConstraintViolation<Driver>> violations = validator.validate(yourObjectToValidate);
I am extending AbstractRepositoryEventListener in order to create a md5 hash of an photo and save it with the object.
I'd like to abort saving the photo altogether in the event of an exception.
#Component
public class MyHandler extends AbstractRepositoryEventListener<Photo> {
#Autowired
PhotoService photoService;
#Override
public void onBeforeSave(Photo photo) {
File originalPhoto = new File(foto.getUriOriginal());
try {
String hash = photoService.getHash(originalPhoto);
photo.setHash(hash);
} catch ( IOException | NoSuchAlgorithmException e ) {
e.printStackTrace();
}
}
}
You may throw an instance of RuntimeException. It will get Spring to rollback.
There are other more comprehensive ways, details of which you can find here.
If someone ever have this same problem, here's a better approach.
The goal here is basically to validate an entity.
Spring already provides a ValidatingRepositoryEventListener that uses validators to achieve this goal. Not only will the saving be "aborted", but also the error message will be provided to the client.
It is important to notice that automatic discovery of validators seem to have a bug with a workaround described here.
It is also possible to create custom validation annotations, as described in the link below, resulting in a more reusable code.
In this particular instance, the Validator would look something like this:
#Component("beforeSavePhotoValidator")
public class PhotoValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return Photo.class.equals(clazz);
}
#Override
public void validate(Object obj, Errors errors) {
if (customValidationIsInvalid(obj)){
errors.rejectValue(
"<invalidFieldName>",
"<errorMessageCode>"
);
}
}
}
Observe that:
customValidationIsInvalid, invalidFieldName and errorMessageCode should be appropriately implemented
the errorMessageCode must be set in the ValidationMessages.properties file
the workaround must be implemented, or the validator manually registered
I need to make an extension point for custom validation rules in java. Can you help me to find the best way to do it?
My code looks like this
...
public myClass() {
...
//some business logic
customValidator.validate(event); //custom validator
...
}
I know that it is suitable to use base Validator interface and implement it with custom validators.
interface Validator {
public static Boolean validate();
}
public class TrueValidator implements Validator {
public static Boolean validate() { return true;}
}
public class TrueValidator implements Validator {
public static Boolean validate() { return false;}
}
I want to know what is the best pattern of calling validation depending on some String variable. Is it okay just to get class with Reflection API? I will get my String from database, create Class and create instance of it.
The other solution I know is to make Validator factory and get Validator by String variable, but I think that it is too excessive.
Can you recommend me somethink?
You basically want to instantiate a validator based on a string? There are multiple possible implementations and I can't tell which one is best, but the implementation you choose should be abstracted away in a factory. You do not want your code littered with logic to find and instantiate those validators from strings.
E.g.
public interface Validator {
public boolean validate(ThingToValidate thingToValidate);
}
public final class TrueValidator implements Validator {
//Note that the method is not static
public boolean validate(ThingToValidate thingToValidate) {
return true;
}
}
public interface ValidatorFactory {
public Validator createFromType(String type);
}
//Concrete validation factory using reflection
public final class ReflectiveValidatorFactory implements ValidatorFactory {
public Validator createFromType(String type) {
/*Use reflection to resolve the class based on the interface
and naming conventions and/or annotations.
You may also cache the validator to avoid re-resolving it.*/
}
}
//Concrete validation factory where validator types are hard-coded.
public final class HardcodedValidatorFactory implements ValidatorFactory {
public Validator createFromType(String type) {
switch (type) {
case 'True': return new TrueValidator();
//...
}
}
}
//Example of a client class that would use the ValidatorFactory
public final class ValidationService {
private final ValidatorFactory validatorFactory;
public ValidationService(ValidatorFactory validatorFactory) {
this.validatorFactory = validatorFactory;
}
public boolean validate(String validatorType, ThingToValidate thingToValidate) {
Validator validator = validatorFactory.createFromType(validatorType);
return validator.validate(thingToValidate);
}
}
Please note that your Valiator.validate method shouldn't be static! I understand that since validators are stateless you may want to re-use the same instance hence the idea to make the validate method static, but doing so will make your design much less flexible and testable.
If you wish to ensure that the same validator instance is re-used, then you can make sure that only one concrete ValidatorFactory is instantiated in your Composition Root and that this factory caches the validators.
I don't know Spring, however to understand some of the java patterns I was reading through Spring tutorials and stumbled onto below code. By the look of it, this looks like classic decorator, but then you see ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);. I am somewhat uncomfortable using utility to delegate to the other validator since I feel it would be difficult to unit test these static invocations(although it can be achieved with PowerMock but am not a big fan of the same). I feel addressValidator.validate() is pretty much cleaner.Since I am writing a custom validator for one my applications, I just wanted to get some thoughts on these approaches.
public class CustomerValidator implements Validator {
private final Validator addressValidator;
public CustomerValidator(Validator addressValidator) {
this.addressValidator = addressValidator;
}
public boolean supports(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
Customer customer = (Customer) target;
try {
errors.pushNestedPath("address");
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
} finally {
errors.popNestedPath();
}
}
}
I was thinking about a good implementation for validators. My service method starts like this:
if(badSituation()){
return Response.status(400).entity("bad situtaion").build();
}
if(badSituation2()){
return Response.status(400).entity("bad situtaion2").build();
}
...
if(badSituationN()){
return Response.status(400).entity("bad situtaionN").build();
}
Since validators multiply really fast I have decided to refactor them to some design pattern. I was thinking about Chain of Responsibility or Composite, however I had a problem with practical realization. Can someone suggest how this code should be refactored?
You can use the Cor Pattern for the validation "Behavior" : Each of your validators would implement a base ChainedValidator interface (some of the behavior can be moved to a parent abstract class as it is the same for all chain members):
public class MyFirstValidator implements ChainedValidator{
//This CoR implementation has also a 'Composite' background
ChainedValidator nextValidator;
#Override
private void doValidate(Request request) throws ValidationException
{
if(badSituation){
//throw validation exception
}
}
#Override
public void doChainValidate(Request request) throws ValidationException
{//This method can be moved to a parent abstract class
doValidate(request);
if(nextValidator!=null){
nextValidator.doChainValidate(request);
}
}
private void attachValidator(ChainedValidator newValidator) throws ValidationException
{//same as previous method
if(nextValidator!=null){
nextValidator.attachValidator(request);
}else{
nextValidator=newValidator;
}
}
//setters & other methods
}
On your Controllers/Web tier Service classes, you can inject the first ChainedValidator of the validation chain and call doChainValidate :
public class WebTierService{
ChainedValidator validator;
public Response serviceMethod(Request request){
try{
//...
validator.doChainValidate(request);
//...
}catch(ValidationException e){
return Response.status(400).entity(e.getMessage()).build();
}
}
}
As you can see, the logic is 'fluid' (No if else check depending on type of validation error) and adding a new validator is relatively simple (validator.attachValidator()) which makes the logic extensible and clean.