Jump to content

Make something thats generic , variable... (Hard to explain in one sentence )

- - - - -

  • Please log in to reply
5 replies to this topic

#1
PunkDudez

PunkDudez

    Newbie

  • Members
  • PipPip
  • 10 posts
Hi people.

I have a problem and its kind of difficult to describe, so I start from a sample:


    public boolean example(DataObject object) {

        boolean isValid = false;

        /**

         * ClassA, ClassB, ... extend from DataObject

         */

        if (object.getClass().equals(ClassA.class)) {

            ClassA obj = (ClassA) object;

            Set<ConstraintViolation<ClassA>> violations = validator.validate(obj);

            Iterator it = violations.iterator();

            if (it.hasNext()) {

                while (it.hasNext()) {

                    ConstraintViolation<ClassA> message = (ConstraintViolation<ClassA>) it.next();

                    // Handling my errors messages... message.getMessage();

                }

            } else {

                isValid = true;

            }

        } else if (object.getClass().equals(ClassB.class)) {

            Class<?> obj = (ClassB) object;

            Set<ConstraintViolation<ClassB>> violations = validator.validate(obj);

            Iterator it = violations.iterator();

            if (it.hasNext()) {

                while (it.hasNext()) {

                    ConstraintViolation<ClassB> message = (ConstraintViolation<ClassB>) it.next();

                    // Handling my errors messages... message.getMessage();

                }

            } else {

                isValid = true;

            }

        }

        return isValid;

    }


When you read the code above, you might notice that I repeat my code in each IF bloc. The only difference are the generics... (ClassA, ClassB). Hence the fact that there are 7 subclasses in the future. (7 if bloc's in the future).

Is there a possibility to make this generics variable so it would result in :

    public boolean example(DataObject object) {

        boolean isValid = false;

        ClassType type = object.class;


            type obj = (type ) object;

            Set<ConstraintViolation<type >> violations = validator.validate(obj);

            Iterator it = violations.iterator();

            if (it.hasNext()) {

                while (it.hasNext()) {

                    ConstraintViolation<type > message = (ConstraintViolation<type >) it.next();

                    // Handling my errors messages... message.getMessage();

                }

            } else {

                isValid = true;

            }

        return isValid;

    }


Additional information:
I am trying to validate my objects by Annotation validation JSR303 (Hibnernate validation). The error messages will be send to a central service which will hold all the messages occurred in validations.

Thanks for your time

PS : If problem is not clear, please warn me and I'll try to rewrite...

#2
Sinipull

Sinipull

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 386 posts
object.getClass().equals(ClassB.class)
instead of this, use
object instanceof ClassB
which is much simpler to read.

If all the classes need different code for validation, use an interface. Name it something like "Validateable".

public interface Validateable{
     public boolean isvalid(Validator validator);     
}

make all your classes implement the "Validateable" interface and the method inside. So you can directly access the classes own isvalid() method, which makes it look much cleaner + there's no need for sequence of 'if's, because you can just write something like this:
if(object instanceof Validateable){
      if(((Validateable)object).isvalid(validator)){
             //do your stuff
      }
}


otherwise, if your classes all look very similar for some reason, you should look over your design patterns, because there's always a way to write reusable code.

#3
gregwarner

gregwarner

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 853 posts
  • Location:Arkansas
I'm not sure I understand. As long as all your derived classes are subclasses of DataObject, you should be able to cast each one to a DataObject and treat it as such. Example:

public boolean example(DataObject object) {

    ...

    Set<ConstraintViolation<DataObject>> violations = validator.validate(object);

    ...

}

To call this function, you would have to cast the subclass to a DataObject every time since Java doesn't support covariance and contravariance in method parameters, only return types:

// Assuming ClassA extends DataObject:

ClassA a = new ClassA();

example((DataObject) a);


In your example method, you can also use the instanceof operator to check whether the object is a subclass type or not:

public boolean example (DataObject object) {

    ...

    if (object instanceof ClassA) {

        ...

    }

    ...

}


Forgive me if I'm not understanding your question perfectly, but I'm pretty sure that should work.

EDIT: Sinipull beat me to the punch.
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.

– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#4
PunkDudez

PunkDudez

    Newbie

  • Members
  • PipPip
  • 10 posts
Ok, I read some useful stuff for writing some cleaner code, but still I don't have the answer I am looking for.
Maybe because I focused to much on the inheritance...

So I will try to explain with this (explaining ain't my talent) :

Set<ConstraintViolation<ClassA >> violations = validator.validate(obj);

The method 'validate(obj)' will return a Set<ConstraintViolation<ClassA >>. This is because the 'obj' is an instance of ClassA. I cannot change this, it is not a method I wrote, it is from the Hibernate Validator api.

This is a part of the code I will have to execute with every object type i have (ClassA, ClassB, ClassC, ClassD, ...).
    public boolean example(DataObject object) {

            [B]Set<ConstraintViolation<ClassA>> violations = validator.validate(obj);[/B]

            Iterator it = violations.iterator();

            if (it.hasNext()) {

                while (it.hasNext()) {

                   [B] ConstraintViolation<ClassA> message = (ConstraintViolation<ClassA >) it.next();[/B]

                    // Following a lot of other code

                }

            } else {

                isValid = true;

            }

        return isValid;

    }
The bold lines are the only lines that will change depending the Object type (class).
All other code will be the same (even if I work with an Interface to implement an isValid() method, I will just repeat the same code for every Object type but separated from each other )

Now is there a possibility to have these 2 bold lines variable (only the generic changes) ?
My goal is to have ONE method, able to execute the validation of any kind/type of object which has Annotation Constraints/Validations (JSR303 Hibernate Validation Implementation) in my domain.
One methods means centralized code, which can be reused every time without any new or further implementation...

(Additional Info : All this object types that I will have to validate extend from DataObject (Because all objects types share on similar field))

I tried this, but it does not work...

Set<ConstraintViolation<? extends DataObject >> violations = validator.validate(obj);


Thanks already for the previous replies.

Ian

#5
gregwarner

gregwarner

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 853 posts
  • Location:Arkansas

Quote


Set<ConstraintViolation<? extends DataObject >> violations = validator.validate(obj);

Don't do that. Just treat it as a DataObject, since ClassA is derived from DataObject:

Set<ConstraintViolation<DataObject>> violations = validator.validate(obj);


Just use the suggestion by Sinipull above to make sure the class is validateable. I think that will work. Let me know if it doesn't.
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.

– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#6
PunkDudez

PunkDudez

    Newbie

  • Members
  • PipPip
  • 10 posts

gregwarner said:

Don't do that. Just treat it as a DataObject, since ClassA is derived from DataObject:

Set<ConstraintViolation<DataObject>> violations = validator.validate(obj);

This results in a "Incompatible type"
Found "package . DataObject "
Required "package . ClassA "

gregwarner said:

Just use the suggestion by Sinipull above to make sure the class is validateable. I think that will work. Let me know if it doesn't.
Using a interface for for my POJO's will just result in splitting up the multiple (almost same) occurrences of my code but implemented in the isValid() method of each POJO... And also writing code (business logic = validation) in a plain data object isn't really a good practice I think ? I prefer creating a ValidationService for example (I am working in Spring 3.0). Keeps it clean and centralized, this would result in classes witch have a particular and straight forward responsibility.

I guess reading about new Design Patterns might the best solution if i cannot make the generics variable.

EDIT
The following works now...
Set<ConstraintViolation<DataObject>> violations = validator.validate(obj);
First it didn't work out but the 'obj' was defined as a ClassA instance, but now I just work directly with the 'object' instance which resembles 'DataObject'.
A small example to illustrate..

Fails :

private void test(DataObject object){

Set<ConstraintViolation<DataObject>> violations;

      if(object instanceof ClassA){

            ClassA [B][U]obj [/U][/B]= (ClassA) object;

            [I]// doing some stuff which are Class A specific ...[/I]

            violations = validator.validate([B][U]obj[/U][/B]);

      }

}

Works :

private void test(DataObject [B][U]object[/U][/B]){

Set<ConstraintViolation<DataObject>> violations;

      if(object instanceof ClassA){

            ClassA obj = (ClassA) object;

            [I]// doing some stuff which are Class A specific ...[/I]

            violations = validator.validate([B][U]object[/U][/B]);

      }

}


This works perfect, I'll have to do some refactoring for cleaning up and make it smoother code but thanks anyway gregwarner. You pushed me the good direction, I just had to do some finetuning...

Ian

Edited by PunkDudez, 25 April 2011 - 10:52 PM.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users