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.beans.factory;
018
019import java.io.PrintStream;
020import java.io.PrintWriter;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.springframework.beans.FatalBeanException;
025import org.springframework.core.NestedRuntimeException;
026import org.springframework.lang.Nullable;
027
028/**
029 * Exception thrown when a BeanFactory encounters an error when
030 * attempting to create a bean from a bean definition.
031 *
032 * @author Juergen Hoeller
033 */
034@SuppressWarnings("serial")
035public class BeanCreationException extends FatalBeanException {
036
037        @Nullable
038        private final String beanName;
039
040        @Nullable
041        private final String resourceDescription;
042
043        @Nullable
044        private List<Throwable> relatedCauses;
045
046
047        /**
048         * Create a new BeanCreationException.
049         * @param msg the detail message
050         */
051        public BeanCreationException(String msg) {
052                super(msg);
053                this.beanName = null;
054                this.resourceDescription = null;
055        }
056
057        /**
058         * Create a new BeanCreationException.
059         * @param msg the detail message
060         * @param cause the root cause
061         */
062        public BeanCreationException(String msg, Throwable cause) {
063                super(msg, cause);
064                this.beanName = null;
065                this.resourceDescription = null;
066        }
067
068        /**
069         * Create a new BeanCreationException.
070         * @param beanName the name of the bean requested
071         * @param msg the detail message
072         */
073        public BeanCreationException(String beanName, String msg) {
074                super("Error creating bean with name '" + beanName + "': " + msg);
075                this.beanName = beanName;
076                this.resourceDescription = null;
077        }
078
079        /**
080         * Create a new BeanCreationException.
081         * @param beanName the name of the bean requested
082         * @param msg the detail message
083         * @param cause the root cause
084         */
085        public BeanCreationException(String beanName, String msg, Throwable cause) {
086                this(beanName, msg);
087                initCause(cause);
088        }
089
090        /**
091         * Create a new BeanCreationException.
092         * @param resourceDescription description of the resource
093         * that the bean definition came from
094         * @param beanName the name of the bean requested
095         * @param msg the detail message
096         */
097        public BeanCreationException(@Nullable String resourceDescription, @Nullable String beanName, String msg) {
098                super("Error creating bean with name '" + beanName + "'" +
099                                (resourceDescription != null ? " defined in " + resourceDescription : "") + ": " + msg);
100                this.resourceDescription = resourceDescription;
101                this.beanName = beanName;
102                this.relatedCauses = null;
103        }
104
105        /**
106         * Create a new BeanCreationException.
107         * @param resourceDescription description of the resource
108         * that the bean definition came from
109         * @param beanName the name of the bean requested
110         * @param msg the detail message
111         * @param cause the root cause
112         */
113        public BeanCreationException(@Nullable String resourceDescription, String beanName, String msg, Throwable cause) {
114                this(resourceDescription, beanName, msg);
115                initCause(cause);
116        }
117
118
119        /**
120         * Return the description of the resource that the bean
121         * definition came from, if any.
122         */
123        @Nullable
124        public String getResourceDescription() {
125                return this.resourceDescription;
126        }
127
128        /**
129         * Return the name of the bean requested, if any.
130         */
131        @Nullable
132        public String getBeanName() {
133                return this.beanName;
134        }
135
136        /**
137         * Add a related cause to this bean creation exception,
138         * not being a direct cause of the failure but having occurred
139         * earlier in the creation of the same bean instance.
140         * @param ex the related cause to add
141         */
142        public void addRelatedCause(Throwable ex) {
143                if (this.relatedCauses == null) {
144                        this.relatedCauses = new ArrayList<>();
145                }
146                this.relatedCauses.add(ex);
147        }
148
149        /**
150         * Return the related causes, if any.
151         * @return the array of related causes, or {@code null} if none
152         */
153        @Nullable
154        public Throwable[] getRelatedCauses() {
155                if (this.relatedCauses == null) {
156                        return null;
157                }
158                return this.relatedCauses.toArray(new Throwable[0]);
159        }
160
161
162        @Override
163        public String toString() {
164                StringBuilder sb = new StringBuilder(super.toString());
165                if (this.relatedCauses != null) {
166                        for (Throwable relatedCause : this.relatedCauses) {
167                                sb.append("\nRelated cause: ");
168                                sb.append(relatedCause);
169                        }
170                }
171                return sb.toString();
172        }
173
174        @Override
175        public void printStackTrace(PrintStream ps) {
176                synchronized (ps) {
177                        super.printStackTrace(ps);
178                        if (this.relatedCauses != null) {
179                                for (Throwable relatedCause : this.relatedCauses) {
180                                        ps.println("Related cause:");
181                                        relatedCause.printStackTrace(ps);
182                                }
183                        }
184                }
185        }
186
187        @Override
188        public void printStackTrace(PrintWriter pw) {
189                synchronized (pw) {
190                        super.printStackTrace(pw);
191                        if (this.relatedCauses != null) {
192                                for (Throwable relatedCause : this.relatedCauses) {
193                                        pw.println("Related cause:");
194                                        relatedCause.printStackTrace(pw);
195                                }
196                        }
197                }
198        }
199
200        @Override
201        public boolean contains(@Nullable Class<?> exClass) {
202                if (super.contains(exClass)) {
203                        return true;
204                }
205                if (this.relatedCauses != null) {
206                        for (Throwable relatedCause : this.relatedCauses) {
207                                if (relatedCause instanceof NestedRuntimeException &&
208                                                ((NestedRuntimeException) relatedCause).contains(exClass)) {
209                                        return true;
210                                }
211                        }
212                }
213                return false;
214        }
215
216}