1 /*
2  * Hibernate Validator, declare and validate application constraints
3  *
4  * License: Apache License, Version 2.0
5  * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6  */

7 package org.hibernate.validator.internal.engine;
8
9 import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
10
11 import java.util.HashSet;
12 import java.util.Set;
13
14 import org.hibernate.validator.internal.metadata.aggregated.rule.MethodConfigurationRule;
15 import org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints;
16 import org.hibernate.validator.internal.metadata.aggregated.rule.ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue;
17 import org.hibernate.validator.internal.metadata.aggregated.rule.ParallelMethodsMustNotDefineParameterConstraints;
18 import org.hibernate.validator.internal.metadata.aggregated.rule.ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine;
19 import org.hibernate.validator.internal.metadata.aggregated.rule.VoidMethodsMustNotBeReturnValueConstrained;
20 import org.hibernate.validator.internal.util.CollectionHelper;
21 import org.hibernate.validator.internal.util.stereotypes.Immutable;
22
23 /**
24  * These properties modify the behavior of the {@code Validator} with respect to the Jakarta Bean Validation
25  * specification section 5.6.5. In particular:
26  * <pre>
27  * "Out of the box, a conforming Bean Validation provider must throw a
28  * ConstraintDeclarationException when discovering that any of these rules are violated.
29  * In addition providers may implement alternative, potentially more liberal, approaches
30  * for handling constrained methods in inheritance hierarchies. Possible means for activating
31  * such alternative behavior include provider-specific configuration properties or annotations.
32  * Note that client code relying on such alternative behavior is not portable between Bean
33  * Validation providers."
34  * </pre>
35  *
36  * @author Chris Beckey &lt;cbeckey@paypal.com&gt;
37  * @author Guillaume Smet
38  */

39 public class MethodValidationConfiguration {
40
41     private boolean allowOverridingMethodAlterParameterConstraint = false;
42     private boolean allowMultipleCascadedValidationOnReturnValues = false;
43     private boolean allowParallelMethodsDefineParameterConstraints = false;
44
45     @Immutable
46     private Set<MethodConfigurationRule> configuredRuleSet;
47
48     private MethodValidationConfiguration(boolean allowOverridingMethodAlterParameterConstraint, boolean allowMultipleCascadedValidationOnReturnValues,
49             boolean allowParallelMethodsDefineParameterConstraints) {
50         this.allowOverridingMethodAlterParameterConstraint = allowOverridingMethodAlterParameterConstraint;
51         this.allowMultipleCascadedValidationOnReturnValues = allowMultipleCascadedValidationOnReturnValues;
52         this.allowParallelMethodsDefineParameterConstraints = allowParallelMethodsDefineParameterConstraints;
53
54         this.configuredRuleSet = buildConfiguredRuleSet( allowOverridingMethodAlterParameterConstraint, allowMultipleCascadedValidationOnReturnValues,
55                 allowParallelMethodsDefineParameterConstraints );
56     }
57
58     /**
59      * @return {@code trueif more than one return value within a class hierarchy can be marked for cascaded
60      * validation, {@code false} otherwise.
61      */

62     public boolean isAllowOverridingMethodAlterParameterConstraint() {
63         return this.allowOverridingMethodAlterParameterConstraint;
64     }
65
66     /**
67      * @return {@code trueif more than one return value within a class hierarchy can be marked for cascaded
68      * validation, {@code false} otherwise.
69      */

70     public boolean isAllowMultipleCascadedValidationOnReturnValues() {
71         return this.allowMultipleCascadedValidationOnReturnValues;
72     }
73
74     /**
75      * @return {@code trueif constraints on methods in parallel class hierarchy are allowed, {@code false} otherwise.
76      */

77     public boolean isAllowParallelMethodsDefineParameterConstraints() {
78         return this.allowParallelMethodsDefineParameterConstraints;
79     }
80
81     /**
82      * Return an unmodifiable Set of MethodConfigurationRule that are to be
83      * enforced based on the configuration.
84      *
85      * @return a set of method configuration rules based on this configuration state
86      */

87     public Set<MethodConfigurationRule> getConfiguredRuleSet() {
88         return configuredRuleSet;
89     }
90
91     private static Set<MethodConfigurationRule> buildConfiguredRuleSet(boolean allowOverridingMethodAlterParameterConstraint,
92             boolean allowMultipleCascadedValidationOnReturnValues, boolean allowParallelMethodsDefineParameterConstraints) {
93         HashSet<MethodConfigurationRule> result = newHashSet( 5 );
94
95         if ( !allowOverridingMethodAlterParameterConstraint ) {
96             result.add( new OverridingMethodMustNotAlterParameterConstraints() );
97         }
98
99         if ( !allowParallelMethodsDefineParameterConstraints ) {
100             result.add( new ParallelMethodsMustNotDefineParameterConstraints() );
101         }
102
103         result.add( new VoidMethodsMustNotBeReturnValueConstrained() );
104
105         if ( !allowMultipleCascadedValidationOnReturnValues ) {
106             result.add( new ReturnValueMayOnlyBeMarkedOnceAsCascadedPerHierarchyLine() );
107         }
108
109         result.add( new ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue() );
110
111         return CollectionHelper.toImmutableSet( result );
112     }
113
114     @Override
115     public int hashCode() {
116         final int prime = 31;
117         int result = 1;
118         result = prime * result + ( allowMultipleCascadedValidationOnReturnValues ? 1231 : 1237 );
119         result = prime * result + ( allowOverridingMethodAlterParameterConstraint ? 1231 : 1237 );
120         result = prime * result + ( allowParallelMethodsDefineParameterConstraints ? 1231 : 1237 );
121         return result;
122     }
123
124     @Override
125     public boolean equals(Object obj) {
126         if ( this == obj ) {
127             return true;
128         }
129         if ( obj == null ) {
130             return false;
131         }
132         if ( getClass() != obj.getClass() ) {
133             return false;
134         }
135         MethodValidationConfiguration other = (MethodValidationConfiguration) obj;
136         if ( allowMultipleCascadedValidationOnReturnValues != other.allowMultipleCascadedValidationOnReturnValues ) {
137             return false;
138         }
139         if ( allowOverridingMethodAlterParameterConstraint != other.allowOverridingMethodAlterParameterConstraint ) {
140             return false;
141         }
142         if ( allowParallelMethodsDefineParameterConstraints != other.allowParallelMethodsDefineParameterConstraints ) {
143             return false;
144         }
145         return true;
146     }
147
148     public static class Builder {
149
150         private boolean allowOverridingMethodAlterParameterConstraint = false;
151         private boolean allowMultipleCascadedValidationOnReturnValues = false;
152         private boolean allowParallelMethodsDefineParameterConstraints = false;
153
154         public Builder() {
155         }
156
157         public Builder(MethodValidationConfiguration template) {
158             allowOverridingMethodAlterParameterConstraint = template.allowOverridingMethodAlterParameterConstraint;
159             allowMultipleCascadedValidationOnReturnValues = template.allowMultipleCascadedValidationOnReturnValues;
160             allowParallelMethodsDefineParameterConstraints = template.allowParallelMethodsDefineParameterConstraints;
161         }
162
163         /**
164          * Define whether overriding methods that override constraints should throw a {@code ConstraintDefinitionException}.
165          * The default value is {@code false}, i.e. do not allow.
166          *
167          * See Section 5.6.5 of the Jakarta Bean Validation Specification, specifically
168          * <pre>
169          * "In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may
170          * be declared on overridden or implemented methods, nor may parameters be marked for cascaded validation.
171          * This would pose a strengthening of preconditions to be fulfilled by the caller."
172          * </pre>
173          *
174          * @param allow flag determining whether validation will allow overriding to alter parameter constraints.
175          *
176          * @return {@code this} following the chaining method pattern
177          */

178         public Builder allowOverridingMethodAlterParameterConstraint(boolean allow) {
179             this.allowOverridingMethodAlterParameterConstraint = allow;
180             return this;
181         }
182
183         /**
184          * Define whether more than one constraint on a return value may be marked for cascading validation are allowed.
185          * The default value is {@code false}, i.e. do not allow.
186          *
187          * "One must not mark a method return value for cascaded validation more than once in a line of a class hierarchy.
188          * In other words, overriding methods on sub types (be it sub classes/interfaces or interface implementations)
189          * cannot mark the return value for cascaded validation if the return value has already been marked on the
190          * overridden method of the super type or interface."
191          *
192          * @param allow flag determining whether validation will allow multiple cascaded validation on return values.
193          *
194          * @return {@code this} following the chaining method pattern
195          */

196         public Builder allowMultipleCascadedValidationOnReturnValues(boolean allow) {
197             this.allowMultipleCascadedValidationOnReturnValues = allow;
198             return this;
199         }
200
201         /**
202          * Define whether parallel methods that define constraints should throw a {@code ConstraintDefinitionException}. The
203          * default value is {@code false}, i.e. do not allow.
204          *
205          * See Section 5.6.5 of the Jakarta Bean Validation Specification, specifically
206          * "If a sub type overrides/implements a method originally defined in several parallel types of the hierarchy
207          * (e.g. two interfaces not extending each other, or a class and an interface not implemented by said class),
208          * no parameter constraints may be declared for that method at all nor parameters be marked for cascaded validation.
209          * This again is to avoid an unexpected strengthening of preconditions to be fulfilled by the caller."
210          *
211          * @param allow flag determining whether validation will allow parameter constraints in parallel hierarchies
212          *
213          * @return {@code this} following the chaining method pattern
214          */

215         public Builder allowParallelMethodsDefineParameterConstraints(boolean allow) {
216             this.allowParallelMethodsDefineParameterConstraints = allow;
217             return this;
218         }
219
220         public boolean isAllowOverridingMethodAlterParameterConstraint() {
221             return allowOverridingMethodAlterParameterConstraint;
222         }
223
224         public boolean isAllowMultipleCascadedValidationOnReturnValues() {
225             return allowMultipleCascadedValidationOnReturnValues;
226         }
227
228         public boolean isAllowParallelMethodsDefineParameterConstraints() {
229             return allowParallelMethodsDefineParameterConstraints;
230         }
231
232         public MethodValidationConfiguration build() {
233             return new MethodValidationConfiguration(
234                     allowOverridingMethodAlterParameterConstraint,
235                     allowMultipleCascadedValidationOnReturnValues,
236                     allowParallelMethodsDefineParameterConstraints
237             );
238         }
239     }
240 }
241