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 org.springframework.lang.Nullable;
020import org.springframework.util.Assert;
021import org.springframework.util.ObjectUtils;
022
023/**
024 * Encapsulates a field error, that is, a reason for rejecting a specific
025 * field value.
026 *
027 * <p>See the {@link DefaultMessageCodesResolver} javadoc for details on
028 * how a message code list is built for a {@code FieldError}.
029 *
030 * @author Rod Johnson
031 * @author Juergen Hoeller
032 * @since 10.03.2003
033 * @see DefaultMessageCodesResolver
034 */
035@SuppressWarnings("serial")
036public class FieldError extends ObjectError {
037
038        private final String field;
039
040        @Nullable
041        private final Object rejectedValue;
042
043        private final boolean bindingFailure;
044
045
046        /**
047         * Create a new FieldError instance.
048         * @param objectName the name of the affected object
049         * @param field the affected field of the object
050         * @param defaultMessage the default message to be used to resolve this message
051         */
052        public FieldError(String objectName, String field, String defaultMessage) {
053                this(objectName, field, null, false, null, null, defaultMessage);
054        }
055
056        /**
057         * Create a new FieldError instance.
058         * @param objectName the name of the affected object
059         * @param field the affected field of the object
060         * @param rejectedValue the rejected field value
061         * @param bindingFailure whether this error represents a binding failure
062         * (like a type mismatch); else, it is a validation failure
063         * @param codes the codes to be used to resolve this message
064         * @param arguments the array of arguments to be used to resolve this message
065         * @param defaultMessage the default message to be used to resolve this message
066         */
067        public FieldError(String objectName, String field, @Nullable Object rejectedValue, boolean bindingFailure,
068                        @Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {
069
070                super(objectName, codes, arguments, defaultMessage);
071                Assert.notNull(field, "Field must not be null");
072                this.field = field;
073                this.rejectedValue = rejectedValue;
074                this.bindingFailure = bindingFailure;
075        }
076
077
078        /**
079         * Return the affected field of the object.
080         */
081        public String getField() {
082                return this.field;
083        }
084
085        /**
086         * Return the rejected field value.
087         */
088        @Nullable
089        public Object getRejectedValue() {
090                return this.rejectedValue;
091        }
092
093        /**
094         * Return whether this error represents a binding failure
095         * (like a type mismatch); otherwise it is a validation failure.
096         */
097        public boolean isBindingFailure() {
098                return this.bindingFailure;
099        }
100
101
102        @Override
103        public boolean equals(@Nullable Object other) {
104                if (this == other) {
105                        return true;
106                }
107                if (!super.equals(other)) {
108                        return false;
109                }
110                FieldError otherError = (FieldError) other;
111                return (getField().equals(otherError.getField()) &&
112                                ObjectUtils.nullSafeEquals(getRejectedValue(), otherError.getRejectedValue()) &&
113                                isBindingFailure() == otherError.isBindingFailure());
114        }
115
116        @Override
117        public int hashCode() {
118                int hashCode = super.hashCode();
119                hashCode = 29 * hashCode + getField().hashCode();
120                hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getRejectedValue());
121                hashCode = 29 * hashCode + (isBindingFailure() ? 1 : 0);
122                return hashCode;
123        }
124
125        @Override
126        public String toString() {
127                return "Field error in object '" + getObjectName() + "' on field '" + this.field +
128                                "': rejected value [" + ObjectUtils.nullSafeToString(this.rejectedValue) + "]; " +
129                                resolvableToString();
130        }
131
132}