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.metadata.location;
8
9 import java.lang.annotation.ElementType;
10 import java.lang.reflect.Type;
11 import java.lang.reflect.TypeVariable;
12
13 import org.hibernate.validator.internal.engine.path.PathImpl;
14 import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind;
15 import org.hibernate.validator.internal.properties.Callable;
16 import org.hibernate.validator.internal.properties.Constrainable;
17 import org.hibernate.validator.internal.properties.Field;
18 import org.hibernate.validator.internal.properties.Getter;
19 import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
20 import org.hibernate.validator.internal.util.StringHelper;
21
22 /**
23  * Represents the location (e.g. a bean, field or method parameter) of a constraint and provides logic related to it,
24  * e.g. for appending the location to a given property path.
25  * <p>
26  * Note that while the validation engine works on the aggregated meta-model (which e.g. provides a unified view for
27  * properties, be them represented via fields or getter methods) most of the time, in some situations the physical
28  * element which hosts a constraint is relevant. This includes
29  * <ul>
30  * <li>retrieval of property values to be validated (either field or getter access)</li>
31  * <li>constraint validator resolution; a field and the corresponding getter method may have different types, causing
32  * potentially different validators to kick in for the constraints declared on either element</li>
33  * <li>determination of a constraint's scope (locally defined or up in the hierarchy)</li>
34  * </ul>
35  *
36  * @author Hardy Ferentschik
37  * @author Gunnar Morling
38  */

39 public interface ConstraintLocation {
40
41     static ConstraintLocation forClass(Class<?> declaringClass) {
42         return new BeanConstraintLocation( declaringClass );
43     }
44
45     static ConstraintLocation forField(Field field) {
46         return new FieldConstraintLocation( field );
47     }
48
49     static ConstraintLocation forGetter(Getter getter) {
50         return new GetterConstraintLocation( getter );
51     }
52
53     static ConstraintLocation forTypeArgument(ConstraintLocation delegate, TypeVariable<?> typeParameter, Type typeOfAnnotatedElement) {
54         return new TypeArgumentConstraintLocation( delegate, typeParameter, typeOfAnnotatedElement );
55     }
56
57     static ConstraintLocation forReturnValue(Callable callable) {
58         return new ReturnValueConstraintLocation( callable );
59     }
60
61     static ConstraintLocation forCrossParameter(Callable callable) {
62         return new CrossParameterConstraintLocation( callable );
63     }
64
65     static ConstraintLocation forParameter(Callable callable, int index) {
66         return new ParameterConstraintLocation( callable, index );
67     }
68
69     /**
70      * Returns the class hosting this location.
71      */

72     Class<?> getDeclaringClass();
73
74     /**
75      * Returns the member represented by this location.
76      *
77      * @return the member represented by this location. Will be {@code null} when this location represents a type.
78      */

79     Constrainable getConstrainable();
80
81     /**
82      * Returns the type to be used when resolving constraint validators for constraints at this location. Note that this
83      * is not always the same type as the type of the element described by this location; E.g. the wrapper type will is
84      * used for constraint validator resolution, if a constraint is declared in an element with a primitive type.
85      *
86      * @return The type to be used when resolving constraint validators for constraints at this location
87      */

88     Type getTypeForValidatorResolution();
89
90     /**
91      * Appends a node representing this location to the given property path.
92      */

93     void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path);
94
95     /**
96      * Obtains the value of this location from the parent. The type of the passed parent depends on the location type,
97      * e.g. a bean would be passed for a {@link AbstractPropertyConstraintLocation} but an
98      * object array for a {@link ParameterConstraintLocation}.
99      */

100     Object getValue(Object parent);
101
102     /**
103      * Returns the nature of the constraint location.
104      */

105     ConstraintLocationKind getKind();
106
107     enum ConstraintLocationKind {
108         TYPE( ElementType.TYPE ),
109         CONSTRUCTOR( ElementType.CONSTRUCTOR ),
110         METHOD( ElementType.METHOD ),
111         PARAMETER( ElementType.PARAMETER ),
112         FIELD( ElementType.FIELD ),
113         GETTER( ElementType.METHOD ),
114         TYPE_USE( ElementType.TYPE_USE );
115
116         private final ElementType elementType;
117
118         ConstraintLocationKind(ElementType elementType) {
119             this.elementType = elementType;
120         }
121
122         public ElementType getElementType() {
123             return elementType;
124         }
125
126         public boolean isExecutable() {
127             return this == CONSTRUCTOR || isMethod();
128         }
129
130         public boolean isMethod() {
131             return this == METHOD || this == GETTER;
132         }
133
134         public static ConstraintLocationKind of(ConstrainedElementKind constrainedElementKind) {
135             switch ( constrainedElementKind ) {
136                 case CONSTRUCTOR:
137                     return ConstraintLocationKind.CONSTRUCTOR;
138                 case FIELD:
139                     return ConstraintLocationKind.FIELD;
140                 case METHOD:
141                     return ConstraintLocationKind.METHOD;
142                 case PARAMETER:
143                     return ConstraintLocationKind.PARAMETER;
144                 case TYPE:
145                     return ConstraintLocationKind.TYPE;
146                 case GETTER:
147                     return ConstraintLocationKind.GETTER;
148                 default:
149                     throw new IllegalArgumentException(
150                             StringHelper.format( "Constrained element kind '%1$s' not supported.", constrainedElementKind ) );
151             }
152         }
153     }
154 }
155