1
7 package org.hibernate.validator.internal.metadata.raw;
8
9 import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
10 import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
11
12 import java.lang.invoke.MethodHandles;
13 import java.util.Collections;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Set;
17
18 import javax.validation.metadata.ConstraintDescriptor;
19
20 import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder;
21 import org.hibernate.validator.internal.metadata.core.MetaConstraint;
22 import org.hibernate.validator.internal.properties.Callable;
23 import org.hibernate.validator.internal.util.CollectionHelper;
24 import org.hibernate.validator.internal.util.logging.Log;
25 import org.hibernate.validator.internal.util.logging.LoggerFactory;
26 import org.hibernate.validator.internal.util.stereotypes.Immutable;
27
28
36 public class ConstrainedExecutable extends AbstractConstrainedElement {
37
38 private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
39
40 private final Callable callable;
41
42
45 @Immutable
46 private final List<ConstrainedParameter> parameterMetaData;
47
48 private final boolean hasParameterConstraints;
49
50 @Immutable
51 private final Set<MetaConstraint<?>> crossParameterConstraints;
52
53
63 public ConstrainedExecutable(
64 ConfigurationSource source,
65 Callable callable,
66 Set<MetaConstraint<?>> returnValueConstraints,
67 Set<MetaConstraint<?>> typeArgumentConstraints,
68 CascadingMetaDataBuilder cascadingMetaDataBuilder) {
69 this(
70 source,
71 callable,
72 Collections.<ConstrainedParameter>emptyList(),
73 Collections.<MetaConstraint<?>>emptySet(),
74 returnValueConstraints,
75 typeArgumentConstraints,
76 cascadingMetaDataBuilder
77 );
78 }
79
80
94 public ConstrainedExecutable(
95 ConfigurationSource source,
96 Callable callable,
97 List<ConstrainedParameter> parameterMetaData,
98 Set<MetaConstraint<?>> crossParameterConstraints,
99 Set<MetaConstraint<?>> returnValueConstraints,
100 Set<MetaConstraint<?>> typeArgumentConstraints,
101 CascadingMetaDataBuilder cascadingMetaDataBuilder) {
102 super(
103 source,
104 callable.getConstrainedElementKind(),
105 returnValueConstraints,
106 typeArgumentConstraints,
107 cascadingMetaDataBuilder
108 );
109
110 this.callable = callable;
111
112 if ( parameterMetaData.size() != callable.getParameterCount() ) {
113 throw LOG.getInvalidLengthOfParameterMetaDataListException(
114 callable,
115 callable.getParameterCount(),
116 parameterMetaData.size()
117 );
118 }
119
120 this.crossParameterConstraints = CollectionHelper.toImmutableSet( crossParameterConstraints );
121 this.parameterMetaData = CollectionHelper.toImmutableList( parameterMetaData );
122 this.hasParameterConstraints = hasParameterConstraints( parameterMetaData ) || !crossParameterConstraints.isEmpty();
123 }
124
125
136 public ConstrainedParameter getParameterMetaData(int parameterIndex) {
137 if ( parameterIndex < 0 || parameterIndex > parameterMetaData.size() - 1 ) {
138 throw LOG.getInvalidExecutableParameterIndexException(
139 callable,
140 parameterIndex
141 );
142 }
143
144 return parameterMetaData.get( parameterIndex );
145 }
146
147
155 public List<ConstrainedParameter> getAllParameterMetaData() {
156 return parameterMetaData;
157 }
158
159 public Set<MetaConstraint<?>> getCrossParameterConstraints() {
160 return crossParameterConstraints;
161 }
162
163
173 @Override
174 public boolean isConstrained() {
175 return super.isConstrained() || hasParameterConstraints;
176 }
177
178
185 public boolean hasParameterConstraints() {
186 return hasParameterConstraints;
187 }
188
189 public Callable getCallable() {
190 return callable;
191 }
192
193 @Override
194 public String toString() {
195 return "ConstrainedExecutable [executable=" + callable
196 + ", parameterMetaData=" + parameterMetaData
197 + ", hasParameterConstraints=" + hasParameterConstraints + "]";
198 }
199
200 private boolean hasParameterConstraints(List<ConstrainedParameter> parameterMetaData) {
201 for ( ConstrainedParameter oneParameter : parameterMetaData ) {
202 if ( oneParameter.isConstrained() ) {
203 return true;
204 }
205 }
206
207 return false;
208 }
209
210
220 public boolean isEquallyParameterConstrained(ConstrainedExecutable other) {
221 if ( !getDescriptors( crossParameterConstraints ).equals( getDescriptors( other.crossParameterConstraints ) ) ) {
222 return false;
223 }
224
225 int i = 0;
226 for ( ConstrainedParameter parameter : parameterMetaData ) {
227 ConstrainedParameter otherParameter = other.getParameterMetaData( i );
228
229 if ( !parameter.getCascadingMetaDataBuilder().equals( otherParameter.getCascadingMetaDataBuilder() )
230 || !getDescriptors( parameter.getConstraints() ).equals( getDescriptors( otherParameter.getConstraints() ) ) ) {
231 return false;
232 }
233 i++;
234 }
235
236 return true;
237 }
238
239
248 public ConstrainedExecutable merge(ConstrainedExecutable other) {
249 ConfigurationSource mergedSource = ConfigurationSource.max( source, other.source );
250
251 List<ConstrainedParameter> mergedParameterMetaData = newArrayList( parameterMetaData.size() );
252 int i = 0;
253 for ( ConstrainedParameter parameter : parameterMetaData ) {
254 mergedParameterMetaData.add( parameter.merge( other.getParameterMetaData( i ) ) );
255 i++;
256 }
257
258 Set<MetaConstraint<?>> mergedCrossParameterConstraints = newHashSet( crossParameterConstraints );
259 mergedCrossParameterConstraints.addAll( other.crossParameterConstraints );
260
261 Set<MetaConstraint<?>> mergedReturnValueConstraints = newHashSet( constraints );
262 mergedReturnValueConstraints.addAll( other.constraints );
263
264 Set<MetaConstraint<?>> mergedTypeArgumentConstraints = new HashSet<>( typeArgumentConstraints );
265 mergedTypeArgumentConstraints.addAll( other.typeArgumentConstraints );
266
267 CascadingMetaDataBuilder mergedCascadingMetaDataBuilder = cascadingMetaDataBuilder.merge( other.cascadingMetaDataBuilder );
268
269 return new ConstrainedExecutable(
270 mergedSource,
271 callable,
272 mergedParameterMetaData,
273 mergedCrossParameterConstraints,
274 mergedReturnValueConstraints,
275 mergedTypeArgumentConstraints,
276 mergedCascadingMetaDataBuilder
277 );
278 }
279
280 private Set<ConstraintDescriptor<?>> getDescriptors(Iterable<MetaConstraint<?>> constraints) {
281 Set<ConstraintDescriptor<?>> descriptors = newHashSet();
282
283 for ( MetaConstraint<?> constraint : constraints ) {
284 descriptors.add( constraint.getDescriptor() );
285 }
286
287 return descriptors;
288 }
289
290 @Override
291 public int hashCode() {
292 final int prime = 31;
293 int result = super.hashCode();
294 result = prime * result + callable.hashCode();
295 return result;
296 }
297
298 @Override
299 public boolean equals(Object obj) {
300 if ( this == obj ) {
301 return true;
302 }
303 if ( !super.equals( obj ) ) {
304 return false;
305 }
306 if ( getClass() != obj.getClass() ) {
307 return false;
308 }
309 ConstrainedExecutable other = (ConstrainedExecutable) obj;
310 if ( !callable.equals( other.callable ) ) {
311 return false;
312 }
313 return true;
314 }
315 }
316