[bv-dev] Extractors vs cascading logic (was Re: Support for constraints on container values (e.g. Collection<@Email String>))

Gunnar Morling gunnar at hibernate.org
Wed Nov 23 02:46:32 EST 2016


Hey Matt,

It's great to see you here, has been a while :)

Regarding that annotation, could you provide a small example tailored to
the issue at hand to show what you have in mind with it? It's not fully
clear to me yet.

Thanks,

--Gunnar



2016-11-22 21:22 GMT+01:00 Matt Benson <mbenson at apache.org>:

> In Therian there is a custom annotation to specify a method that
> provides a Type value at runtime. Specifically It allows one to
> designate a method that returns an instance of the Typed interface
> from Apache Commons Lang 3.x.
>
> Annotation: https://github.com/mbenson/therian/blob/master/core/src/
> main/java/therian/BindTypeVariable.java
> Example: https://github.com/mbenson/therian/blob/master/core/src/
> main/java/therian/operation/Transform.java
> Utilities: https://github.com/mbenson/therian/blob/master/core/src/
> main/java/therian/util/Types.java#L88
>
> An approach like this would of course put some onus onto users with
> the payoff of being very explicit. In any case, it might provide food
> for thought on the subject.
>
> Matt
>
>
> On Tue, Nov 22, 2016 at 1:15 PM, Emmanuel Bernard
> <emmanuel at hibernate.org> wrote:
> >
> > On 21 Nov 2016, at 14:07, Emmanuel Bernard <emmanuel at hibernate.org>
> wrote:
> >
> >
> > On 7 Nov 2016, at 23:42, Hendrik Ebbers <hendrik.ebbers at me.com> wrote:
> >
> > Let’s say we have the following 2 interfaces:
> >
> > public interface CachedValue<V> {
> >     V getCachedValue();
> > }
> >
> > public interface RealValue<V> {
> >     V getRealValue();
> > }
> >
> > Based on this interfaces we can easily create a new class that implements
> > both interfaces:
> >
> > public class CachableValue<V> implements CachedValue<V>, RealValue<V> {
> >
> >     private V cachedValue;
> >
> >     @Override
> >     public V getCachedValue() {
> >         return cachedValue;
> >     }
> >
> >     @Override
> >     public V getRealValue() {
> >         V realValue = receiveValueFromServer();
> >         cachedValue = realValue;
> >         return realValue;
> >     }
> >
> >     private V receiveValueFromServer() {
> >         return ServerConnector.getCurrentValue(); //Some fake code
> >     }
> > }
> >
> > Let’s try to add a constraint annotation to validate the content of such
> a
> > CachableValue:
> >
> > private CachableValue<@NotEmpty String> myValue;
> >
> > Based on this definition you have absolutely no idea if the @NotEmpty
> > annotation is defined for the real value, the cached value or both
> values.
> > From my point of view this is a big problem. Until now its was always
> easy
> > to see how the validation of a model should work based on the validation
> > information (annotations) in the model. With this new approach you have
> no
> > idea what will happen.
> >
> > The most simple solution would be to add the support only to some special
> > container / wrapper classes like collections, JavaFX properties, etc. I
> > think this is a bad idea since new default might come to future versions
> of
> > JavaSE and JavaEE (or maybe Spring) and that won’t be supported. Based on
> > this I think that it will be a must to support all wrapper types.
> >
> >
> > Interesting.
> >
> > I did think about extractors of subtypes but not extractors of parallel
> > types.
> > I have been thinking about it and explored a few paths:
> > - validating all parallel extractors
> > - use one
> > - validate none
> > - fail
> >
> > In the end, I think the cleanest solution is to follow what Ceylon and
> Java
> > do for default methods, they don’t allow ambiguous use and force a
> > redefinition.
> > http://stackoverflow.com/questions/16764791/how-does-
> java-8-new-default-interface-model-works-incl-diamond-
> multiple-inhe#16788295
> >
> > In practice for us, if there are extractors for CachedValue and for
> > RealValue, then CachableValue should fail and require the definition of
> an
> > explicit CachableValue extractor.
> > What is interesting in this case is that CachableValue extractor can be
> see
> > as either:
> > - a ManyContainerValuesExtractor that will return getCachedValue and
> > getRealValue just like a Collection would return get(0) and get(1). This
> > approach does not reflect the path difference though
> > - or two SingleContainerValueExtractor from the same container type and
> the
> > same value type (*)
> >
> > (*) this is something we do not allow for the moment, we have a unique
> > extractor per container + value type. We need to think about how to make
> > that work and still allow people to override extractors.
> >
> > So back to your original concern of uncertainty, I think forcing a more
> > specific extractor solves the uncertainty that you mentioned. Granted,
> the
> > user would have to know the extractor(s) behavior but in many ways,
> people
> > do need to know about that regardless.
> >
> > Thoughts?
> >
> >
> > Gunnar and I discussed this problem further and the proposal at large, in
> > particular in the light of his alternative proposal (section 3).
> >
> > The main question we have is how common are constraints on user defined
> type
> > like:
> >
> > - CachableValue<V> // CacheableValue<@Email String> value;
> > - Tuple<V1,V2> // Tuple<@Email String, @Valid Address> userIdAndAddress;
> > - …
> >
> > Here I am excluding:
> > - Optional
> > - Collection and Map (and all Iterable really)
> > - even Collections of non Java languages (Scala, Ceylon, Kotlin if they
> have
> > their own collection type, etc)
> >
> > If constraints on the user defined types described above are common,
> then we
> > need a more systematic solution than imposing to write an extractor for
> each
> > of these cases.
> > If they are uncommon and the only containers are Optional, Collection,
> Map,
> > JavaFX containers and other language collections, or more generally
> > framework provided containers, then a requiring an extractor
> implementation
> > is not too problematic.
> >
> >
> > To put some context, the overall BVAL-508 proposal addresses several
> things:
> > - how to extract value from a container
> > - where to express constraints on the values of a container
> > - how and when the cascading logic should work
> >
> > In my proposal. extractors are explicit implementations (with built-in as
> > well as custom implementations). The extractors:
> > - extract the value(s)
> > - express the link between the extractor and the type parameter (and thus
> > the parameterized type)
> > - must be implemented explicitly for each tuple extractor / type
> parameter
> >
> > Gunnar has an alternative proposal or rather a proposal that builds on
> top
> > of the existing one but provide a default generic extractor logic.
> >
> > If no explicit extractor exists, the following will happen
> >
> > Assuming
> >
> > Tuple<@Email String, @Valid Address> userIdAndAddress;
> >
> > class Tuple<V1, V2> {
> >     V1 v1;
> >     V2 v2;
> >
> >     V1 getV1() { return v1; };
> >     V2 getV2() { return v2; };
> > }
> >
> > The default extractor would look for all getters that return the
> > parameterized type(s) and use the getter as extractor. It then would
> apply
> > the constraint.
> > In our case, the code would validate getV1() against @Email and getV2()
> will
> > be cascaded.
> >
> > This is elegant and extremely regular. But it has a very ugly angle:
> should
> > we validate the getters or the fields or the getters then the fields?
> >
> > The rule proposed by Gunnar is to validate the getters first because he
> > likes them better and then look for fields with no corresponding getter
> and
> > validate them.
> >
> > Assuming
> >
> > Tuple<@Email String, @Valid Address> userIdAndAddress;
> >
> > class Tuple<V1, V2> {
> >     V1 v1;
> >     V1 v1b;
> >     V2 v2;
> >
> >     V1 getV1() { return v1; };
> >     V2 getV2() { return v2; };
> > }
> >
> > In this example, the code would validate getV1() against @Email, getV2()
> > will be cascaded and v1b will be validated against @Email.
> >
> > This alternative proposal has two advantages:
> > - it reduces the number of necessary extractor implementations (assuming
> the
> > relevant elements have getters)
> > - it makes the problem described by Hendrik with CacheableValue fully
> > deterministic
> > - it makes the logic of cascading very regular (for non collection at
> least)
> > - it still requires the ability to write custom extractors for collection
> > type containers
> >
> > I have to admit I hate the arbitrary logic of choosing getters and then
> > fields.
> >
> > So my questions to you are:
> > - how common do you see the Tuple, CacheableValue and other user defined
> > type needing validation?
> > - would you be satisfied by the getter approach as an extractor?
> > - what do you think of the getter priority logic?
> >
> > What do you think?
> >
> > Emmanuel
> >
> > _______________________________________________
> > 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/beanvalidation-dev/attachments/20161123/55bead9a/attachment.html 


More information about the beanvalidation-dev mailing list