On 23 Nov 2016, at 09:06, Gunnar Morling <gunnar@hibernate.org> wrote:

2016-11-21 17:08 GMT+01:00 Emmanuel Bernard <emmanuel@hibernate.org>:

On 7 Nov 2016, at 23:42, Hendrik Ebbers <hendrik.ebbers@me.com> wrote:
Next to the „applyTo“ value all the constraint annotations needs additional information to really validate all the given examples. In addition a plugin must be present that defines how we can get the internal value(s) of a class (in this case „StringProperty“).
Here are some code snippets that use additional information in the annotations to define the validation:

@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS)
@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, applyToInternalDepth = 2)
@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, applyToInternalDepth = 3)
private List<List<List<StringProperty>>> spooky;

@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, valueContainerClass = RealValue.class)
private RealValue<String> myValue;

The „applyToInternalDepth“ value is used to define how often the validator should get the internal value (depth). In the given example „@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, applyToInternalDepth = 3)“ would validate the content of the „StringProperty“. In addition we need some information for the container if the container implements several interfaces. This could be defined in the annotation, too. In the example this is defined by the „valueContainerClass“ value.

Hopefully we can converge on my idea not to have to add valueContainerClass (see the other emails). But you do need a way to identify the correct type parameter targeted. This is equivalent to the @ExtractedValue which today has typeParameterHost and either typeParameterIndex or typeParameterName to uniquely identify them.

On the depth approach, your example would be more easily rewritten as 

    @NotEmpty List<@NotEmpty List<@NotEmpty List<@NotEmpty StringProperty>>> spooky;

which clarifies everything. But let’s assume we have a type ListOfListOfListOfStringProperty type. do we really want to support

@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS)
@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, applyToInternalDepth = 2)
@NotEmpty(applyTo = ConstraintsApplyTo.INTERNALS, applyToInternalDepth = 3)
private ListOfListOfListOfStringProperty spooky;

or even

// support nested levels by positioning ConstraintsApplyTo at the right level
private List<@NotEmpty List<@NotEmpty @NotEmpty(applyTo = ConstraintsApplyTo.CONTAINED_VALUES) ListOfStringProperty>> spooky;

Or do we throw the towel and say that nested levels are not supported for non parameterized type use locations? What I am realizing now is that this option is available essentially to support containers that do not offer parameterized type. And in a previous email, I am questioning that use case.

I'm also not convinced of this. In a way it seems to me like breaking encapsulation.

When dealing with a type such as ListOfStringListsProperty, you don't know it's inner works from a variable declaration. Hence I'm doubting that you should be allowed to apply constraints to them from the outside. It's getting more apparent when thinking of more real-world domain-specific types:

    public class CustomerContacts {
        List<List<String>> contacts; // one single inner list contains the contacts valid at a given time

I don't think it makes sense to allow application of constraints "from the outside" when dealing with a property of CustomerContacts. It makes assumptions on the implementation of that type which is a dangerous thing to do. What if the implementation of CustomerContacts changes to be map-based? Existing constraint configurations given at the usage side would have to be adapted then.

Instead the constraints should be declared within CustomerContacts itself.

It's different for generic types. When dealing with a type like List<List<String>>, its "inner workings" are apparent to the user, i.e. it's reasonable to allow them to apply constraints to the elements of the inner list for instance.

Ah interesting point of view. I’ve never thought of it that way.

I think what I had in mind when I said containers with no parameterized type is the Java 4 style collections that only have raw type support.

Collection emails;

But back to the question, is that even a valid use case in 2016?