views:

214

answers:

3

I'm using Hibernate validator and trying to create a little util class:

public class DataRecordValidator<T> {
    public void validate(Class<T> clazz, T validateMe) {
        ClassValidator<T> validator = new ClassValidator<T>(clazz);
        InvalidValue[] errors = validator.getInvalidValues(validateMe);
        [...]
    }
}

Question is, why do I need to supply the Class<T> clazz parameter when executing new ClassValidator<T>(clazz)? Why can't you specify:

  1. T as in ClassValidator<T>(T)?
  2. validateMe.getClass() as in ClassValidator<T>(validateMe.getClass())

I get errors when I try to do both options.

Edit: I understand why #1 doesn't work. But I don't get why #2 doesn't work. I currently get this error with #2:

cannot find symbol
symbol  : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>)
location: class org.hibernate.validator.ClassValidator<T>

Note: Hibernate API method is (here)

A: 

Because ClassValidator is requiring a Class object as its parameter, NOT an instance of the class in question. Bear in mind you might be able to do what you're trying to do with this code:

ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass());
Jherico
Thanks. Why can't you use `validateMe.getClass()` or `T.class`?
Marcus
I thought that too... but I get this error: `cannot find symbol` / `symbol : constructor ClassValidator(java.lang.Class<capture#454 of ? extends java.lang.Object>)` / `location: class org.hibernate.validator.ClassValidator<T>`
Marcus
Look at my edit about how to declare your ClassValidator
Jherico
Nope: `found : ? extends T / required: class or interface without bounds` , `symbol : method getInvalidValues(T) location: class org.hibernate.validator.ClassValidator<capture#536 of ? extends T>`
Marcus
+8  A: 

Because T is not a value - it's just a hint for the compiler. The JVM has no clue of the T. You can use generics only as a type for the purposes of type checking at compile time.

Ondra Žižka
Thanks. Why then can you not use `validateMe.getClass()`?
Marcus
You __can__ use `getClass()` on any object reference... Just checked, compiler is OK with that.
Ondra Žižka
You can use `validateMe.getClass()`, but there are caveats: if `validateMe` is `null` you get a `NullPointerException`, which may or may not be what you want. And using the current code you could pass a base class (for example validate this `Employee` instance using the rules for its base class `Person`). If you leave out the `Class` parameter that is no longer possible.
Joachim Sauer
+1  A: 

If the validate method is yours, then you can safely skip the Class atribute.

public void validate(T validateMe) {
    ClassValidator<T> validator = 
           new ClassValidator<T>((Class<T>) validateMe.getClass());
    ...
}

But the ClassValidator constructor requires a Class argument.

Using an unsafe cast is not preferred, but in this case it is actually safe if you don't have something like this:

class A {..}
class B extends A {..}

new DataRecordValidator<A>.validate(new B());

If you think you will need to do something like that, include the Class argument in the method. Otherwise you may be getting ClassCastException at runtime, but this is easily debuggable, although it's not quite the idea behind generics.

Bozho
Sadly doesn't work, see my response to @Jherico's post.
Marcus
I made an update, it should be working.
Bozho
Thanks, the `(Class<T>)` was the key!
Marcus