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