001/*
002 * Copyright 2012-2017 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 *      http://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.boot.diagnostics.analyzer;
018
019import java.io.PrintWriter;
020import java.io.StringWriter;
021import java.lang.reflect.Proxy;
022
023import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
024import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
025import org.springframework.boot.diagnostics.FailureAnalysis;
026
027/**
028 * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a
029 * {@link BeanNotOfRequiredTypeException}.
030 *
031 * @author Andy Wilkinson
032 */
033public class BeanNotOfRequiredTypeFailureAnalyzer
034                extends AbstractFailureAnalyzer<BeanNotOfRequiredTypeException> {
035
036        private static final String ACTION = "Consider injecting the bean as one of its "
037                        + "interfaces or forcing the use of CGLib-based "
038                        + "proxies by setting proxyTargetClass=true on @EnableAsync and/or "
039                        + "@EnableCaching.";
040
041        @Override
042        protected FailureAnalysis analyze(Throwable rootFailure,
043                        BeanNotOfRequiredTypeException cause) {
044                if (!Proxy.isProxyClass(cause.getActualType())) {
045                        return null;
046                }
047                return new FailureAnalysis(getDescription(cause), ACTION, cause);
048        }
049
050        private String getDescription(BeanNotOfRequiredTypeException ex) {
051                StringWriter description = new StringWriter();
052                PrintWriter printer = new PrintWriter(description);
053                printer.printf(
054                                "The bean '%s' could not be injected as a '%s' because it is a "
055                                                + "JDK dynamic proxy that implements:%n",
056                                ex.getBeanName(), ex.getRequiredType().getName());
057                for (Class<?> requiredTypeInterface : ex.getRequiredType().getInterfaces()) {
058                        printer.println("\t" + requiredTypeInterface.getName());
059                }
060                return description.toString();
061        }
062
063}