001/*
002 * Copyright 2002-2019 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.beans;
018
019import java.io.PrintStream;
020import java.io.PrintWriter;
021import java.util.StringJoiner;
022
023import org.springframework.lang.Nullable;
024import org.springframework.util.Assert;
025import org.springframework.util.ObjectUtils;
026
027/**
028 * Combined exception, composed of individual PropertyAccessException instances.
029 * An object of this class is created at the beginning of the binding
030 * process, and errors added to it as necessary.
031 *
032 * <p>The binding process continues when it encounters application-level
033 * PropertyAccessExceptions, applying those changes that can be applied
034 * and storing rejected changes in an object of this class.
035 *
036 * @author Rod Johnson
037 * @author Juergen Hoeller
038 * @since 18 April 2001
039 */
040@SuppressWarnings("serial")
041public class PropertyBatchUpdateException extends BeansException {
042
043        /** List of PropertyAccessException objects. */
044        private final PropertyAccessException[] propertyAccessExceptions;
045
046
047        /**
048         * Create a new PropertyBatchUpdateException.
049         * @param propertyAccessExceptions the List of PropertyAccessExceptions
050         */
051        public PropertyBatchUpdateException(PropertyAccessException[] propertyAccessExceptions) {
052                super(null, null);
053                Assert.notEmpty(propertyAccessExceptions, "At least 1 PropertyAccessException required");
054                this.propertyAccessExceptions = propertyAccessExceptions;
055        }
056
057
058        /**
059         * If this returns 0, no errors were encountered during binding.
060         */
061        public final int getExceptionCount() {
062                return this.propertyAccessExceptions.length;
063        }
064
065        /**
066         * Return an array of the propertyAccessExceptions stored in this object.
067         * <p>Will return the empty array (not {@code null}) if there were no errors.
068         */
069        public final PropertyAccessException[] getPropertyAccessExceptions() {
070                return this.propertyAccessExceptions;
071        }
072
073        /**
074         * Return the exception for this field, or {@code null} if there isn't any.
075         */
076        @Nullable
077        public PropertyAccessException getPropertyAccessException(String propertyName) {
078                for (PropertyAccessException pae : this.propertyAccessExceptions) {
079                        if (ObjectUtils.nullSafeEquals(propertyName, pae.getPropertyName())) {
080                                return pae;
081                        }
082                }
083                return null;
084        }
085
086
087        @Override
088        public String getMessage() {
089                StringJoiner stringJoiner = new StringJoiner("; ", "Failed properties: ", "");
090                for (PropertyAccessException exception : this.propertyAccessExceptions) {
091                        stringJoiner.add(exception.getMessage());
092                }
093                return stringJoiner.toString();
094        }
095
096        @Override
097        public String toString() {
098                StringBuilder sb = new StringBuilder();
099                sb.append(getClass().getName()).append("; nested PropertyAccessExceptions (");
100                sb.append(getExceptionCount()).append(") are:");
101                for (int i = 0; i < this.propertyAccessExceptions.length; i++) {
102                        sb.append('\n').append("PropertyAccessException ").append(i + 1).append(": ");
103                        sb.append(this.propertyAccessExceptions[i]);
104                }
105                return sb.toString();
106        }
107
108        @Override
109        public void printStackTrace(PrintStream ps) {
110                synchronized (ps) {
111                        ps.println(getClass().getName() + "; nested PropertyAccessException details (" +
112                                        getExceptionCount() + ") are:");
113                        for (int i = 0; i < this.propertyAccessExceptions.length; i++) {
114                                ps.println("PropertyAccessException " + (i + 1) + ":");
115                                this.propertyAccessExceptions[i].printStackTrace(ps);
116                        }
117                }
118        }
119
120        @Override
121        public void printStackTrace(PrintWriter pw) {
122                synchronized (pw) {
123                        pw.println(getClass().getName() + "; nested PropertyAccessException details (" +
124                                        getExceptionCount() + ") are:");
125                        for (int i = 0; i < this.propertyAccessExceptions.length; i++) {
126                                pw.println("PropertyAccessException " + (i + 1) + ":");
127                                this.propertyAccessExceptions[i].printStackTrace(pw);
128                        }
129                }
130        }
131
132        @Override
133        public boolean contains(@Nullable Class<?> exType) {
134                if (exType == null) {
135                        return false;
136                }
137                if (exType.isInstance(this)) {
138                        return true;
139                }
140                for (PropertyAccessException pae : this.propertyAccessExceptions) {
141                        if (pae.contains(exType)) {
142                                return true;
143                        }
144                }
145                return false;
146        }
147
148}