tags:

views:

407

answers:

7

I have a design problem.

I have two data objects which are instances of say class A and class B. A and B don't have any behavior - they are java beans with getters and setters. I have a Validation interface and 10 implementations of it defining different Validations. I would like to specify in my properties file which Validation applies to which class. Something like this:

class A XYZValidation,ABCValidation

class B: ABCValidation, PPPValidation, etc

How do I write my Validation class so that it serves objects that are instances of Class A OR ClassB, or just about any other Class C that I might want to add in future?

interface Validation {
public boolean check(??);
}

> Just wanted to add this line to say thank you to all those who have responded to this post and to say that I am loving my time here on this amazing website. Stackoverflow rocks!

+8  A: 

Have you thought about using annotations to mark the fields you want to validate in your bean?

If you have 10 different validations you could specify 10 annotations. Then mark the fields using annotations:

@ValideStringIsCapitalCase
private String myString;

@ValidateIsNegative
private int myInt;

With reflection API iterate through all the fields and see if they are marked, something like this:

public static <T> validateBean(T myBean) throws IllegalAccessException {
    Field[] fields = myBean.getClass().getDeclaredFields();
    // This does not take fields of superclass into account
    if (fields != null) {
        for (Field field : allFields) {
            if (field.isAnnotationPresent(ValideStringIsCapitalCase.class)) {
                field.setAccessible(true);
                Object value = field.get(existingEntity);
                // Validate
                field.setAccessible(false);
            }
        }
    }
}

An option would be to mark the whole class with the validator you want to use.

EDIT: remember to include annotation:

@Retention(RetentionPolicy.RUNTIME)

for your annotation interface.

EDIT2: please don't modify the fields directly (as in the example above). Instead access their getters and setters using reflection.

tputkonen
This would mean that the validators for a given class are defined at compile-time while this doesn't have to be the case. It's possible that the same class requires different validations in different use-cases, though.
Huxi
That's true, and Jay has to decide if this would be suitable for his/her use case or does he definitely need to have a property file.
tputkonen
+3  A: 

I've probably misunderstood the question but would something like this suffice:

public class ValidationMappings {
    private Map<Class, Class<Validation>[]> mappings = new HashMap<Class, Class<Validation>[]>();

    public ValidationMappings() {
            mappings.put(A.class, new Class[]{XYZValidation.class, ABCValidation.class});
            mappings.put(B.class, new Class[]{ABCValidation.class, PPPValidation.class});
    }

    public Class[] getValidators(Class cls) {
            if (!mappings.containsKey(cls)) return new Class[]{};
            return mappings.get(cls);
    }
}

When you want to get the list of validators for a particular class, you would then call getValidators(Class cls) and iterate over each validator and create an instance of each and call your check method.

digiarnie
+3  A: 

something like this maybe?

interface Validation {
   public boolean check(Validatable x);
}

interface Validatable {
}


class A implements Validatable {
  ...
}

class Validator {
   public boolean validateObject(Validatable x){
      boolean validated = true;
      ... //read config file, check which validation classes to call
      //for each validation class v in the config file:
          if(!v.check(x)) validated = false;
      return validated;
   }
}
Fortega
I was thinking also in this direction, but I've liked the solution with annotations.
Artem Barger
yeah, me too actually :)
Fortega
I don't like it, since in your check method you must cast Validatable to your concrete object. Generics is a better, and safer, alternative:class Validator<T> { boolean validate(T object); }
dfa
ok, than I suggest combining generics with my solution: <T extends Validatable>
Fortega
The Validatable interface is an artificial constraint that isn't buying you anything. Am I missing something?
Huxi
It prevents you at compile time of trying to pass objects to the validateObject() method which aren't actual objects which can be validated.
Fortega
+2  A: 

If you just want it to deal with any object then it'll be Object's that your interface

public boolean check(Object o);

Unless you want to use some marker interface to tag classes that are suitable for validation

objects
+2  A: 

Did you mean:

public interface Validation<T> {
    boolean check(T object)
}
uudashr
+1, this is The Answer [tm] :-)
dfa
An interface like that wouldn't allow a duck-type like validation, i.e. only requiring that a certain method with a certain return value is present. Instead, it would require that this method is defined in an interface. That's an unnecessary restriction.
Huxi
A: 

First of all, I'd use the following interface

interface Validator {
    boolean isValid(Object object);
}

to implicitly document what the return value actually means.

Secondly, I'd suggest to document in the interface what behavior is expected if the Validator doesn't know how to handle the given instance.

interface Validator {
    /**
     * @return false if this validator detects that the given instance is invalid, true if the given object is valid or this Validator can't validate it.
     */
    boolean isValid(Object object);
}

That way, you'd simply have a List of Validators that you could throw your objects at.

The performance impact of incompatible Validators should be negligible if they are implemented properly, e.g. with an early instanceof.

On a side note, I'd use a List of Validators instead of a Set so you can order them according to complexity. Put the cheap (performance-wise) Validators at the start of the List as an optimization.

You could then use a general piece of code for validation, e.g.

public class Validators {
    public static boolean isValid(Object o, Collection<Validator> validators) {
        for(Validator current : validators) {
            if(!current.isValid()) return false;
        }
        return true;
    }
}

Depending on your use-case it might be a good idea to return something different than boolean in your interface. If you need information about what is wrong, e.g. to display it, you'd need to return that info instead.

In that case it might be a good idea to keep the above loop running so you'll get all validation errors instead of only the first.

Huxi
I wonder why somebody voted this down. A comment would have been appreciated...
Huxi
A: 

A Visitor pattern would solve this

Calling the Visitor Validator it's possible to have this:


public interface Validatable {
  public boolean validate(Validator v);

}

public interface Validator {
  public boolean validate(A a);
  public boolean validate(B b);
}

public class A implements Validatable {

  public boolean validate(Validator v){
    return v.validate(this);
  }

}

public class B implements Validatable {

  public void validate(Validator v) {
    return v.validate(this);
  }

}

// Default validator just doesn't know how to 
// validate neither A's, nor B's
public class GenericValidator implements Validator {

  public boolean validate(A a) {
    throw new UnsupportedOperationException("Cannot validate A");
  }

  public boolean validate(B b) {
    throw new UnsupportedOperationException("Cannot validate B");
  }
}

// since XYZValidation is supposed to run only on A's
// it only overrides A validation
public class XYZValidation extends GenericValidator {
  public boolean validate(A a) {
     // validate a
     return isVAlid(a);
  }
}

// since ABCValidation is supposed to run on A's and B's
// it overrides A and B validation
public class ABCValidation extends GenericValidator {
  public boolean validate(A a) {
     // validate a
     return isVAlid(a);
  }

  public boolean validate(B b) {
     // validate b
     return isVAlid(b);
  }
}


// since ABCValidation is supposed to run only on B's
// it overrides A only B validation
public class PPPValidation extends GenericValidator {
  public boolean validate(B b) {
     // validate b
     return isVAlid(b);
  }
}
 
Reginaldo
@Reginaldo think of this: what would happen to your solution if I were to add class C ?
Jay
Feel free to call me a blasphemer but I consider the original Visitor pattern http://en.wikipedia.org/wiki/File:VisitorClassDiagram.svg an anti-pattern in the Java context. It contains a mutual dependency between the visited classes and the Visitor interface that simply isn't necessary in a language that supports RTTI (Run-Time Type Information), like Java. The Visitor needs to know the classes it wants to visit but not the other way around. Additionally, the Visitor interface can easily work on `Object` and handle it only if it can, i.e. just return if(!(o instanceof Whatever)).
Huxi