-
-
Save hferentschik/ea002c2d4f1427226a8b to your computer and use it in GitHub Desktop.
public class Foo { | |
@Valid // !? needed or not? Atm this is needed to trigger iteration | |
private List<@Email String> myEmailList; // that's the case we should primarily address | |
// ... | |
} |
public interface Tuple<V1, V2> { | |
V1 getValue1(); | |
V2 getValue2(); | |
// ... | |
} | |
public interface NonNullTuple<@NotNull V1, @NotNull V2> extends Tuple<V1, V2> { | |
// ... | |
} | |
public class StringTuple implements NonNullTuple<String, String> { | |
@Override | |
public String getValue1() { // so here we safe an @NotNull which we basically inherit | |
return null; | |
} | |
@Override | |
public String getValue2() { | |
return null; | |
} | |
// ... | |
} |
public interface Producer<@NotNull V> { | |
V create(); | |
} | |
public class StringProducer implements Producer<String> { | |
String create(); | |
} |
public interface Tuple<V1, V2> { | |
V1 getValue1(); | |
V2 getValue2(); | |
// ... | |
} | |
public class StringIntegerTuple implements Tuple<@NotNull String, @NotNull @Max(10) Number>> { | |
@Override | |
public String getValue1() { | |
return null; | |
} | |
@Override | |
public Number getValue2() { | |
return null; | |
} | |
} | |
// but would it not just be easier to do: | |
public class StringIntegerTuple implements Tuple<String, Number> { | |
@Override | |
@NotNull | |
public String getValue1() { | |
return null; | |
} | |
@Override | |
@Max(10) | |
public Number getValue2() { | |
return null; | |
} | |
} |
public class TupleUser { | |
@Valid | |
private Tuple<@NotNull String, @NotNull, @Max(10) Number> myStringNumberTuple; // how will we map this to the actual values to be validated? | |
// ... | |
} |
public class TupleWithTypeParameters<@NotNull V1, @NotNull, @Max(10) V2 extends Number> { // Hmm, why not apply constraints on the fields directly? | |
V1 value1; | |
V2 value2; | |
V1 getValue1() { // What do we do? Do we do field or getter validation? We probably would need another annotation to define this | |
return value1; | |
} | |
// ... | |
} | |
Some questions around TupleWithTypeParameters:
- What if we have getter and field? What sort of access do we use? Do we need an
@Access
annotation like in JPA? - What if we don't even have a field or getter for a parameter? Is this an exceptional case?
NonNullTuple seems to me the best use case in favor of specifying constraints on class type parameters. However, one could argue that it is more explicit to add NotNull
to StringTuple
directly (in exchange for some duplication in case you are having more than one non null parameter subclass).
// but would it not just be easier to do
It might be easier in that specific case. But consider that there also could be other occurrences of V1 and V2 (e.g. in method parameters), to which the constraints would be applied as well when following the first approach.
@Valid // !? needed or not?
Why shouldn't it be needed? I don't think type constraints should have any influence on this?
// how will we map this to the actual values to be validated?
My thinking is that we need to merge the meta-data given on the type declaration (i.e. the definition of theTuple
class) with the meta-data of this specific type use (here,Tuple<String, Number>
).
So when retrieving the property meta-data during cascaded validation of myStringNumberTuple
, we'd need to pass in a context, which basically has the following contents:
V1 = @NotNull,
V2 = @NotNull, @Max(10)
Then, when accessing the state of the object in myStringNumberTuple
- e.g. when validating the property getValue1()
, we'd detect it's of type V1 and apply the statically defined meta-data as well as the one passed in from the usage site (as you see we need to define how to access the state, i.e. via getter or field).
Hmm, but would NonNullTuple potentially not violate the LSP?
I have a feeling that in our latest discussions and pull requests we went a bit astray on what HV-877 wants to achieve. The issue is about:
The Foo usage of type annotations is imo the one which is most relevant for now and which is "within" the intend of the spec.
The other cases are interesting and worth investigating. Some of them we might support as Hibernate Validator specific extensions. However, there are several things which need to be discussed in this scope. The reason we said we look at some of these other cases first was the idea that our 'Foo' case follows out of it. Atm I am not so sure about this.