[bv-dev] Metadata API to detect constrained methods and constructors

Emmanuel Bernard emmanuel at hibernate.org
Tue Oct 16 13:06:45 EDT 2012


I put this proposal in.

On Tue 2012-09-11 18:35, Michael Nascimento wrote:
> Your proposal seems fine.
> 
> Regards,
> Michael
> 
> On Tue, Sep 11, 2012 at 6:32 PM, Emmanuel Bernard
> <emmanuel at hibernate.org> wrote:
> > Hi all,
> > I am working on the section explaining how a interception technology
> > integrates with Bean Validation.
> >
> > The proposal is also on the web site at http://beanvalidation.org/proposals/BVAL-274/
> >
> > ## Problem description
> >
> > I was looking at how to compute whether or not method interception needs
> > to occur via on the metadata API.
> >
> > The validation of method-level constraints comprises the following steps:
> >
> > - Intercept the method call to be validated
> > - Validate the parameter values provided by the method caller using Validator#validateParameters() or Validator#validateConstructorParameters().
> > - If this validation yields a non-empty set of constraint violations, throw a ConstraintViolationException wrapping the violations. Otherwise proceed with the actual method invocation.
> > - Validate the result returned by the invoked method using Validator#validateReturnValue() or Validator#validateConstructorReturnValue().
> > - If this validation yields a non-empty set of constraint violations, throw a ConstraintViolationException wrapping the violations. Otherwise return the invocation result to the method caller.
> >
> > I realised that we have a cumbersome API to detect whether or not
> > calling Bean Validation.
> >
> > ```
> >         public boolean interceptMethod(Class<?> type, Method method) {
> >                 BeanDescriptor bean = validator.getConstraintsForClass( type );
> >                 MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >                 return methodDescriptor != null;
> >         }
> >
> >         public boolean validateMethodParametersWithFullNavigation(Class<?> type, Method method) {
> >                 BeanDescriptor bean = validator.getConstraintsForClass( type );
> >                 MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >                 if ( methodDescriptor != null ) {
> >                         boolean validate = false;
> >                         for (ParameterDescriptor paramDescriptor : methodDescriptor.getParameterDescriptors()) {
> >                                 validate = paramDescriptor.hasConstraints() || paramDescriptor.isCascaded();
> >                                 if (validate) {
> >                                         break;
> >                                 }
> >                         }
> >                         return validate;
> >                 }
> >                 else {
> >                         return false;
> >                 }
> >         }
> >
> >         public boolean validateReturnValueWithFullNavigation(Class<?> type, Method method) {
> >                 BeanDescriptor bean = validator.getConstraintsForClass( type );
> >                 MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >                 if ( methodDescriptor != null ) {
> >                         boolean validate = false;
> >                         ReturnValueDescriptor returnValue = methodDescriptor.getReturnValueDescriptor();
> >                         if ( returnValue!=null ) {
> >                             return returnValue.isCascaded() || returnValue.hasConstraints();
> >                         }
> >                         else {
> >                                 return false;
> >                         }
> >                 }
> >                 else {
> >                         return false;
> >                 }
> >         }
> >
> > ```
> >
> > `interceptMethod` is used to decide whether or not we intercept the method
> > at all. it can be used to disable the interceptor entirely.
> >
> > `validateMethodParametersWithFullNavigation` is used to decide whether
> > or not we need to call `validator.validateParameters()`. If no violation
> > is found, we goa nd execute the method.
> >
> > After the method returns, we call
> > `validateReturnValueWithFullNavigation` to decide whether or not to
> > validate return value.
> >
> > There is of course the equivalent for constructor validation.
> >
> > ## Proposal
> >
> > What I am proposing is to add two aggregate methods to
> > `MethodDescriptor` and `ConstructorDescriptor`.
> >
> > ```
> >         /**
> >          * Returns true if method parameters are constrained either:
> >          * - because of a constraint on at least one of the parameters
> >          * - because of a cascade on at least one of the parameters (via {@code @Valid})
> >          * - because of at least a cross-parameter constraint
> >          */
> >         boolean isConstrainedOnParameters();
> >
> >         /**
> >          * Returns true if the method return value is constrained either:
> >          * - because of a constraint on the return value
> >          * - because validation is cascaded on the return value (via {@code @Valid})
> >          */
> >         boolean isConstrainedOnReturnValue();
> > ```
> >
> > The implementation would then become
> >
> > ```
> >         public boolean validateMethodParametersWithMethodDescriptorShortcuts(Class<?> type, Method method) {
> >                 BeanDescriptor bean = validator.getConstraintsForClass( type );
> >                 MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >                 if ( methodDescriptor != null ) {
> >                         return methodDescriptor.isConstrainedOnParameters();
> >                 }
> >                 else {
> >                         return false;
> >                 }
> >         }
> >
> >         public boolean validateMethodReturnValueWithMethodDescriptorShortcuts(Class<?> type, Method method) {
> >                 BeanDescriptor bean = validator.getConstraintsForClass( type );
> >                 MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >                 if ( methodDescriptor != null ) {
> >                         return methodDescriptor.isConstrainedOnReturnValue();
> >                 }
> >                 else {
> >                         return false;
> >                 }
> >         }
> > ```
> >
> > Of course the lookup of `BeanDescriptor` and `MethodDescriptor` only has
> > to be done once. The methods result is also likely being cached by the
> > interceptor being placed and these calls are probably only happening at
> > initialization time.
> >
> > It seems to be it goes in the right
> > direction and expose things at a higher level for the metadata API
> > users.
> > Anyone against the proposed change?
> >
> > An alternative solution is to use the fluent API to find constraints
> >
> >     public boolean validateMethodParametersWithFindConstraintAPI(Class<?> type, Method method) {
> >         BeanDescriptor bean = validator.getConstraintsForClass( type );
> >         MethodDescriptor methodDescriptor = bean.getConstraintsForMethod( method.getName(), method.getParameterTypes() );
> >         if ( methodDescriptor != null ) {
> >             return methodDescriptor.findConstraints().declaredOn( ElementType.PARAMETER ).hasConstraints();
> >         }
> >         else {
> >             return false;
> >         }
> >     }
> >
> > But it's not 100% in line with the `findConstraints()` API: it should only return constraints
> > that are on the element. Plus what is returned by the API is
> > `ConstraintDescriptor` which cannot differentiate where it comes from (parameter or method).
> >
> >
> > 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


More information about the beanvalidation-dev mailing list