[bv-dev] Spec question on ContainerElementTypeDescriptor

Gunnar Morling gunnar at hibernate.org
Wed Jun 21 03:48:08 EDT 2017


> I'm pretty sure wildcards are explicitly mentioned as not being
> supported, and bounds are mentioned there.

I've just prepared
https://github.com/beanvalidation/beanvalidation-spec/pull/210 to
clarify that area.

It says that container element constraints and @Valid are not
supported on the type parameters of generic types and methods as well
as on type arguments with the extends/implements clauses of type
definitions. Implementations are free to experiment with this and we
may lift this limitation in a future revision.

Note that I've removed the note of container element constraints being
unsupported on wildcard type arguments. The reason being that we don't
say something similar for regular (property etc.) constraints. The
spec has been a bit vague on support for constraints on
property/parameter etc. types that are (bounded) wildcards or refer to
type parameters since 1.0. We probably should clarify it at some
point, but it should be done in a general fashion, so I think there's
no need for now to be overly specific for the case of container
element constraints.


2017-06-19 17:50 GMT+02:00 Matt Benson <mbenson at apache.org>:
> On Mon, Jun 19, 2017 at 8:04 AM, Gunnar Morling <gunnar at hibernate.org> wrote:
>> Hi,
>>
>> Putting constraints to type parameters of generic types or methods as
>> well as putting constraints to type arguments in extends/implements
>> clauses isn't supported as of BV 2.0. I thought that's mentioned
>> somewhere in the spec, but couldn't find it during a quick check. If
>> it's indeed missing, I'll add it. We can look into this for 2.1 of
>> course.
>
> I'm pretty sure wildcards are explicitly mentioned as not being
> supported, and bounds are mentioned there. I don't remember type vars
> being included in that. You say "as of BV 2.0." Can I take that to
> mean that you think it's at least possible that this might be
> something the spec should support in the future? Is this basically a
> case of limiting feature creep so that we can finish this iteration
> ASAP?
>
>>
>>> I also suspect that it will make sense to introduce a <container>
>>> element to the XML mapping schema with an optional type, to
>>> (optionally?) house the <container-element-type> elements.
>>
>
> If we've established that the ContainerElementType needs the container
> type to be certain of providing enough information to locate the
> relevant value extractor, then consider the XML mapping. Say we have:
>
> interface ILookup {
>   Map<String, String> getLookup();
> }
>
> class LookupTable extends Hashtable<String, String> {
> }
>
> class LookupImpl implements ILookup {
>   private LookupTable lookupTable;
>
>   LookupTable getLookup() {
>     return lookupTable;
>   }
> }
>
> And we want to constrain the type parameters of the Map in XML:
>
> <bean class="ILookup">
>   <getter name="getLookup">
>     <!-- TBD -->
>   </getter>
> </bean>
>
> We could do:
>
> <container-element-type container-type="java.util.Map" type-argument-index="0">
>   <constraint annotation="NotNull" />
>   <constraint annotation="NotBlank" />
> </container-element-type>
> <container-element-type container-type="java.util.Map" type-argument-index="1">
>   <constraint annotation="NotBlank" />
> </container-element-type>
>
> ... and for simplicity's sake, since the typical container likely has
> a single element type, we probably should continue to support this.
> But should we also allow, e.g.:
>
> <container type="java.util.Map">
>   <container-element-type type-argument-index="0">
>     <constraint annotation="NotNull" />
>     <constraint annotation="NotBlank" />
>   </container-element-type>
>   <container-element-type type-argument-index="1">
>     <constraint annotation="NotBlank" />
>   </container-element-type>
> </container-type>
>
> WRT the optionality of the type argument index, it's clear that for
> containers with a single element type, that could be omitted. Is it
> further intended that where the list of container-element-type
> elements has a length matching the number of type variables declared
> on the container type, these should be understood to specify a 1:1
> ordered correspondence? If so, is there a place (and hopefully a more
> intelligible way ;) ) to clarify that in the spec?
>
> Matt
>
>> Could you elaborate on that point a bit? What exactly is the use case for this?
>>
>> --Gunnar
>>
>>
>>
>> 2017-06-18 17:34 GMT+02:00 Matt Benson <mbenson at apache.org>:
>>> More thoughts in this vein:
>>>
>>> At first I thought that method overrides were the only place you might
>>> have > 1 container class represented, but why wouldn't we support
>>> e.g.:
>>>
>>> class Roles implements Set<@NotEmpty String> {
>>> ...
>>> }
>>>
>>> ? Then it'd be possible to extract container elements even at the bean level.
>>>
>>> Next, consider parameters. the spec currently says that wildcards
>>> aren't supported, but what about:
>>>
>>> <X extends Set<@NotEmpty String> & Iterable<@NotNull String>> void foo(X);
>>>
>>> In this way a parameter could expose multiple container types (pretend
>>> I used unrelated interfaces if that helps). We could save generic
>>> extends support for a future iteration of the spec, but semantically
>>> it makes sense to me so I'd expect we'll eventually have to do it in
>>> any case. I suppose you could even do fields if you annotated some
>>> type parameter of the bean.
>>>
>>> I also suspect that it will make sense to introduce a <container>
>>> element to the XML mapping schema with an optional type, to
>>> (optionally?) house the <container-element-type> elements.
>>>
>>> Matt
>>>
>>>
>>> On Fri, Jun 16, 2017 at 1:38 PM, Gunnar Morling <gunnar at hibernate.org> wrote:
>>>> 2017-06-16 14:06 GMT+02:00 Matt Benson <mbenson at apache.org>:
>>>>> On Fri, Jun 16, 2017 at 2:43 AM, Gunnar Morling <gunnar at hibernate.org> wrote:
>>>>>> Hi Matt,
>>>>>>
>>>>>> Thanks for bringing this up!
>>>>>>
>>>>>> I think adding ContainerElementTypeDescriptor#getContainerClass() is
>>>>>> one thing needed, but it's not enough. Currently we have
>>>>>> List<ContainerElementTypeDescriptor> getContainerElementTypes() on
>>>>>> PropertyDescriptor etc. which returns the container element
>>>>>> descriptors in the order of type arguments. This also doesn't really
>>>>>> fit for User#getRoles().
>>>>>>
>>>>>> So we could make this a Set<ContainerElementTypeDescriptor> instead,
>>>>>> and then each element from that set exposes containerClass and
>>>>>> typeArgumentIndex as you suggest.
>>>>>>
>>>>>> It's getting a bit tricky though to get the effective set of all
>>>>>> container element constraints. Eg. say we have:
>>>>>>
>>>>>>     public interface IUserBase {
>>>>>>         Set<@NotBlank String> getRoles();
>>>>>>     }
>>>>>>
>>>>>>     public interface IUser extends IUserBase {
>>>>>>         Set<@NotEmpty String> getRoles();
>>>>>>     }
>>>>>>
>>>>>>     public class UserImpl implements IUser {
>>>>>>         Roles getRoles();
>>>>>>     }
>>>>>>
>>>>>> Then when querying
>>>>>>
>>>>>>     validator.getConstraintsForClass( IUser.class )
>>>>>>         .getConstraintsForProperty( "roles" )
>>>>>>         .getContainerElementTypes();
>>>>>>
>>>>>> We'd get a set with these elements:
>>>>>>
>>>>>>     - ContainerElementDescriptor(containerClass=IUser.class,
>>>>>> typeArgumentIndex=0, constraints={(type=NotEmpty,
>>>>>> defined=DEFINED_LOCALLY), (type=NotBlank,
>>>>>> defined=DEFINED_IN_HIERARCHY)}
>>>>>>     - ContainerElementDescriptor(containerClass=User.class,
>>>>>> typeArgumentIndex=0, constraints={(type=NotBlank, defined=
>>>>>> DEFINED_LOCALLY)}
>>>>>>
>>>>>
>>>>> I was thinking that the containerClass would be Set.class.
>>>>
>>>> Yes, you are right of course.
>>>>
>>>>>
>>>>>> The descriptor for IUser would have to return the inherited @NotBlank
>>>>>> as per the defined semantics of getConstraintDescriptors(). So one
>>>>>> would have to examine all ContainerElementDescriptors and just collect
>>>>>> the ones that are DEFINED_LOCALLY to have the effective set without
>>>>>> duplicates.
>>>>>>
>>>>>
>>>>> I agree that the set of ContainerElementTypeDescriptors needs to be
>>>>> reduced to unique type parameters, but I'm not sure I'm following your
>>>>> argument above. My suggestion above (containerClass=Set.class) would
>>>>> give an easy way to identify what needs to be collapsed where: onto
>>>>> Set<[0]>. Consider this:
>>>>>
>>>>> public class Roles<S extends System> implements Set<String> {
>>>>>   public S getSystem() {
>>>>>     ...
>>>>>   }
>>>>>   ...
>>>>> }
>>>>>
>>>>> public class UserImpl implements IUser {
>>>>>   public Roles<@ValidSystem UserSystem> getRoles() {
>>>>>     ...
>>>>>   }
>>>>> }
>>>>>
>>>>> Here Roles would implement a custom container type on top of Iterable
>>>>> via Set, so the method would return separate ContainerTypeElements for
>>>>> Roles<[0]> and Set<[0]>. Does that make sense?
>>>>
>>>> Yes, it does.
>>>>
>>>> And in my previous example we'd have getContainerElementTypes() return
>>>> a set with one descriptor:
>>>>
>>>> ContainerElementDescriptor(containerClass=Set.class,
>>>> typeArgumentIndex=0, constraints={(type=NotEmpty, defined=
>>>> DEFINED_IN_HIERARCHY), (type=NotBlank, defined=DEFINED_IN_HIERARCHY)}
>>>>
>>>> (both constraints are defined in the hierarchy from the perspective of UserImpl)
>>>>
>>>>>
>>>>> Matt
>>>>>
>>>>>> The alternative would be to explicitly redeclare
>>>>>> getConstraintDescriptors() for ContainerElementDescriptor and say that
>>>>>> it doesn't expose constraints from the hierarchy. But this would make
>>>>>> it very difficult for the user to find all those constraints applying
>>>>>> to a given container element type (esp. as type arguments could switch
>>>>>> their order in the hierarchy). So that'd not be my preferred route.
>>>>>>
>>>>>> WDYT?
>>>>>>
>>>>>> I've filed https://hibernate.atlassian.net/browse/BVAL-655 for this issue.
>>>>>>
>>>>>> --Gunnar
>>>>>>
>>>>>>
>>>>>> 2017-06-15 17:38 GMT+02:00 Matt Benson <mbenson at apache.org>:
>>>>>>> The various descriptor types return constraint information from the
>>>>>>> entire hierarchy by default. However, in thinking about this I quickly
>>>>>>> encountered a puzzle which I cannot solve using the current version of
>>>>>>> the specification. Consider:
>>>>>>>
>>>>>>> public interface User {
>>>>>>>   Set<@NotEmpty String> getRoles();
>>>>>>> }
>>>>>>>
>>>>>>> public class Roles implements Set<String> {
>>>>>>>  ...
>>>>>>> }
>>>>>>>
>>>>>>> public class UserImpl implements User {
>>>>>>>   @Override
>>>>>>>   public Roles getRoles();
>>>>>>> }
>>>>>>>
>>>>>>> What should the metadata of UserImpl provide? The Iterable value
>>>>>>> extractor is applicable to Roles, but because the return value of the
>>>>>>> getter has been narrowed, there is no type parameter at this point in
>>>>>>> the hierarchy. It seems strange for a PropertyDescriptor of type Roles
>>>>>>> to return a ContainerElementTypeDescriptor with index 0. This example
>>>>>>> would AFAICT apply to e.g. javafx StringProperty as well, so it's
>>>>>>> probably a question we need to resolve, unless I have missed something
>>>>>>> that should be obvious. I think this could be solved if the CETD were
>>>>>>> to explicitly specify the type with which its argument index is
>>>>>>> associated. The alternative would be to require a custom
>>>>>>> ValueExtractor? This seems cumbersome and unnecessary.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Matt
>>>>>>> _______________________________________________
>>>>>>> beanvalidation-dev mailing list
>>>>>>> beanvalidation-dev at lists.jboss.org
>>>>>>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
>>>>>> _______________________________________________
>>>>>> beanvalidation-dev mailing list
>>>>>> beanvalidation-dev at lists.jboss.org
>>>>>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
>>>>> _______________________________________________
>>>>> beanvalidation-dev mailing list
>>>>> beanvalidation-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
>>>> _______________________________________________
>>>> beanvalidation-dev mailing list
>>>> beanvalidation-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
>>> _______________________________________________
>>> beanvalidation-dev mailing list
>>> beanvalidation-dev at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
>> _______________________________________________
>> beanvalidation-dev mailing list
>> beanvalidation-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev
> _______________________________________________
> beanvalidation-dev mailing list
> beanvalidation-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev


More information about the beanvalidation-dev mailing list