001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.validation;
018
019import java.util.List;
020
021import org.springframework.beans.PropertyAccessor;
022import org.springframework.lang.Nullable;
023
024/**
025 * Stores and exposes information about data-binding and validation
026 * errors for a specific object.
027 *
028 * <p>Field names can be properties of the target object (e.g. "name"
029 * when binding to a customer object), or nested fields in case of
030 * subobjects (e.g. "address.street"). Supports subtree navigation
031 * via {@link #setNestedPath(String)}: for example, an
032 * {@code AddressValidator} validates "address", not being aware
033 * that this is a subobject of customer.
034 *
035 * <p>Note: {@code Errors} objects are single-threaded.
036 *
037 * @author Rod Johnson
038 * @author Juergen Hoeller
039 * @see #setNestedPath
040 * @see BindException
041 * @see DataBinder
042 * @see ValidationUtils
043 */
044public interface Errors {
045
046        /**
047         * The separator between path elements in a nested path,
048         * for example in "customer.name" or "customer.address.street".
049         * <p>"." = same as the
050         * {@link org.springframework.beans.PropertyAccessor#NESTED_PROPERTY_SEPARATOR nested property separator}
051         * in the beans package.
052         */
053        String NESTED_PATH_SEPARATOR = PropertyAccessor.NESTED_PROPERTY_SEPARATOR;
054
055
056        /**
057         * Return the name of the bound root object.
058         */
059        String getObjectName();
060
061        /**
062         * Allow context to be changed so that standard validators can validate
063         * subtrees. Reject calls prepend the given path to the field names.
064         * <p>For example, an address validator could validate the subobject
065         * "address" of a customer object.
066         * @param nestedPath nested path within this object,
067         * e.g. "address" (defaults to "", {@code null} is also acceptable).
068         * Can end with a dot: both "address" and "address." are valid.
069         */
070        void setNestedPath(String nestedPath);
071
072        /**
073         * Return the current nested path of this {@link Errors} object.
074         * <p>Returns a nested path with a dot, i.e. "address.", for easy
075         * building of concatenated paths. Default is an empty String.
076         */
077        String getNestedPath();
078
079        /**
080         * Push the given sub path onto the nested path stack.
081         * <p>A {@link #popNestedPath()} call will reset the original
082         * nested path before the corresponding
083         * {@code pushNestedPath(String)} call.
084         * <p>Using the nested path stack allows to set temporary nested paths
085         * for subobjects without having to worry about a temporary path holder.
086         * <p>For example: current path "spouse.", pushNestedPath("child") ->
087         * result path "spouse.child."; popNestedPath() -> "spouse." again.
088         * @param subPath the sub path to push onto the nested path stack
089         * @see #popNestedPath
090         */
091        void pushNestedPath(String subPath);
092
093        /**
094         * Pop the former nested path from the nested path stack.
095         * @throws IllegalStateException if there is no former nested path on the stack
096         * @see #pushNestedPath
097         */
098        void popNestedPath() throws IllegalStateException;
099
100        /**
101         * Register a global error for the entire target object,
102         * using the given error description.
103         * @param errorCode error code, interpretable as a message key
104         */
105        void reject(String errorCode);
106
107        /**
108         * Register a global error for the entire target object,
109         * using the given error description.
110         * @param errorCode error code, interpretable as a message key
111         * @param defaultMessage fallback default message
112         */
113        void reject(String errorCode, String defaultMessage);
114
115        /**
116         * Register a global error for the entire target object,
117         * using the given error description.
118         * @param errorCode error code, interpretable as a message key
119         * @param errorArgs error arguments, for argument binding via MessageFormat
120         * (can be {@code null})
121         * @param defaultMessage fallback default message
122         */
123        void reject(String errorCode, @Nullable Object[] errorArgs, @Nullable String defaultMessage);
124
125        /**
126         * Register a field error for the specified field of the current object
127         * (respecting the current nested path, if any), using the given error
128         * description.
129         * <p>The field name may be {@code null} or empty String to indicate
130         * the current object itself rather than a field of it. This may result
131         * in a corresponding field error within the nested object graph or a
132         * global error if the current object is the top object.
133         * @param field the field name (may be {@code null} or empty String)
134         * @param errorCode error code, interpretable as a message key
135         * @see #getNestedPath()
136         */
137        void rejectValue(@Nullable String field, String errorCode);
138
139        /**
140         * Register a field error for the specified field of the current object
141         * (respecting the current nested path, if any), using the given error
142         * description.
143         * <p>The field name may be {@code null} or empty String to indicate
144         * the current object itself rather than a field of it. This may result
145         * in a corresponding field error within the nested object graph or a
146         * global error if the current object is the top object.
147         * @param field the field name (may be {@code null} or empty String)
148         * @param errorCode error code, interpretable as a message key
149         * @param defaultMessage fallback default message
150         * @see #getNestedPath()
151         */
152        void rejectValue(@Nullable String field, String errorCode, String defaultMessage);
153
154        /**
155         * Register a field error for the specified field of the current object
156         * (respecting the current nested path, if any), using the given error
157         * description.
158         * <p>The field name may be {@code null} or empty String to indicate
159         * the current object itself rather than a field of it. This may result
160         * in a corresponding field error within the nested object graph or a
161         * global error if the current object is the top object.
162         * @param field the field name (may be {@code null} or empty String)
163         * @param errorCode error code, interpretable as a message key
164         * @param errorArgs error arguments, for argument binding via MessageFormat
165         * (can be {@code null})
166         * @param defaultMessage fallback default message
167         * @see #getNestedPath()
168         */
169        void rejectValue(@Nullable String field, String errorCode,
170                        @Nullable Object[] errorArgs, @Nullable String defaultMessage);
171
172        /**
173         * Add all errors from the given {@code Errors} instance to this
174         * {@code Errors} instance.
175         * <p>This is a convenience method to avoid repeated {@code reject(..)}
176         * calls for merging an {@code Errors} instance into another
177         * {@code Errors} instance.
178         * <p>Note that the passed-in {@code Errors} instance is supposed
179         * to refer to the same target object, or at least contain compatible errors
180         * that apply to the target object of this {@code Errors} instance.
181         * @param errors the {@code Errors} instance to merge in
182         */
183        void addAllErrors(Errors errors);
184
185        /**
186         * Return if there were any errors.
187         */
188        boolean hasErrors();
189
190        /**
191         * Return the total number of errors.
192         */
193        int getErrorCount();
194
195        /**
196         * Get all errors, both global and field ones.
197         * @return a list of {@link ObjectError} instances
198         */
199        List<ObjectError> getAllErrors();
200
201        /**
202         * Are there any global errors?
203         * @return {@code true} if there are any global errors
204         * @see #hasFieldErrors()
205         */
206        boolean hasGlobalErrors();
207
208        /**
209         * Return the number of global errors.
210         * @return the number of global errors
211         * @see #getFieldErrorCount()
212         */
213        int getGlobalErrorCount();
214
215        /**
216         * Get all global errors.
217         * @return a list of {@link ObjectError} instances
218         */
219        List<ObjectError> getGlobalErrors();
220
221        /**
222         * Get the <i>first</i> global error, if any.
223         * @return the global error, or {@code null}
224         */
225        @Nullable
226        ObjectError getGlobalError();
227
228        /**
229         * Are there any field errors?
230         * @return {@code true} if there are any errors associated with a field
231         * @see #hasGlobalErrors()
232         */
233        boolean hasFieldErrors();
234
235        /**
236         * Return the number of errors associated with a field.
237         * @return the number of errors associated with a field
238         * @see #getGlobalErrorCount()
239         */
240        int getFieldErrorCount();
241
242        /**
243         * Get all errors associated with a field.
244         * @return a List of {@link FieldError} instances
245         */
246        List<FieldError> getFieldErrors();
247
248        /**
249         * Get the <i>first</i> error associated with a field, if any.
250         * @return the field-specific error, or {@code null}
251         */
252        @Nullable
253        FieldError getFieldError();
254
255        /**
256         * Are there any errors associated with the given field?
257         * @param field the field name
258         * @return {@code true} if there were any errors associated with the given field
259         */
260        boolean hasFieldErrors(String field);
261
262        /**
263         * Return the number of errors associated with the given field.
264         * @param field the field name
265         * @return the number of errors associated with the given field
266         */
267        int getFieldErrorCount(String field);
268
269        /**
270         * Get all errors associated with the given field.
271         * <p>Implementations should support not only full field names like
272         * "name" but also pattern matches like "na*" or "address.*".
273         * @param field the field name
274         * @return a List of {@link FieldError} instances
275         */
276        List<FieldError> getFieldErrors(String field);
277
278        /**
279         * Get the first error associated with the given field, if any.
280         * @param field the field name
281         * @return the field-specific error, or {@code null}
282         */
283        @Nullable
284        FieldError getFieldError(String field);
285
286        /**
287         * Return the current value of the given field, either the current
288         * bean property value or a rejected update from the last binding.
289         * <p>Allows for convenient access to user-specified field values,
290         * even if there were type mismatches.
291         * @param field the field name
292         * @return the current value of the given field
293         */
294        @Nullable
295        Object getFieldValue(String field);
296
297        /**
298         * Return the type of a given field.
299         * <p>Implementations should be able to determine the type even
300         * when the field value is {@code null}, for example from some
301         * associated descriptor.
302         * @param field the field name
303         * @return the type of the field, or {@code null} if not determinable
304         */
305        @Nullable
306        Class<?> getFieldType(String field);
307
308}