From b9a09fcd64fc1ec628d665f97d359ecef055ccbc Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 2 Jun 2017 11:05:40 +0100 Subject: [PATCH] Abandon failure analysis if start of cycle cannot be determined Previously, BeanCurrentlyInCreationFailureAnalyzer would return a FailureAnalysis for any BeanCurrentlyInCreationException even if it could not determine where the cycle begins. This could lead to an inaccurate diagram of the cycle being output. This commit updates BeanCurrentlyInCreationFailureAnalyzer so that it abandons its analysis and returns null if it is unable to determine where the cycle begins. Closes gh-8164 --- ...eanCurrentlyInCreationFailureAnalyzer.java | 47 ++++++++++++++++--- ...rrentlyInCreationFailureAnalyzerTests.java | 9 +++- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzer.java b/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzer.java index 47d803ccd2..39cc45163c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzer.java +++ b/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,28 +39,40 @@ class BeanCurrentlyInCreationFailureAnalyzer @Override protected FailureAnalysis analyze(Throwable rootFailure, BeanCurrentlyInCreationException cause) { - List cycle = new ArrayList(); + DependencyCycle dependencyCycle = findCycle(rootFailure); + if (dependencyCycle == null) { + return null; + } + return new FailureAnalysis(buildMessage(dependencyCycle), null, cause); + } + + private DependencyCycle findCycle(Throwable rootFailure) { + List beansInCycle = new ArrayList(); Throwable candidate = rootFailure; int cycleStart = -1; while (candidate != null) { BeanInCycle beanInCycle = BeanInCycle.get(candidate); if (beanInCycle != null) { - int index = cycle.indexOf(beanInCycle); + int index = beansInCycle.indexOf(beanInCycle); if (index == -1) { - cycle.add(beanInCycle); + beansInCycle.add(beanInCycle); } cycleStart = (cycleStart == -1 ? index : cycleStart); } candidate = candidate.getCause(); } - String message = buildMessage(cycle, cycleStart); - return new FailureAnalysis(message, null, cause); + if (cycleStart == -1) { + return null; + } + return new DependencyCycle(beansInCycle, cycleStart); } - private String buildMessage(List beansInCycle, int cycleStart) { + private String buildMessage(DependencyCycle dependencyCycle) { StringBuilder message = new StringBuilder(); message.append(String.format("The dependencies of some of the beans in the " + "application context form a cycle:%n%n")); + List beansInCycle = dependencyCycle.getBeansInCycle(); + int cycleStart = dependencyCycle.getCycleStart(); for (int i = 0; i < beansInCycle.size(); i++) { BeanInCycle beanInCycle = beansInCycle.get(i); if (i == cycleStart) { @@ -77,6 +89,27 @@ class BeanCurrentlyInCreationFailureAnalyzer return message.toString(); } + private static final class DependencyCycle { + + private final List beansInCycle; + + private final int cycleStart; + + private DependencyCycle(List beansInCycle, int cycleStart) { + this.beansInCycle = beansInCycle; + this.cycleStart = cycleStart; + } + + public List getBeansInCycle() { + return this.beansInCycle; + } + + public int getCycleStart() { + return this.cycleStart; + } + + } + private static final class BeanInCycle { private final String name; diff --git a/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java b/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java index 0067c03d39..49c7b3e39b 100644 --- a/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.util.List; import org.junit.Test; +import org.springframework.beans.factory.BeanCurrentlyInCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalyzer; @@ -116,6 +117,12 @@ public class BeanCurrentlyInCreationFailureAnalyzerTests { assertThat(lines.get(11)).isEqualTo("└─────┘"); } + @Test + public void cycleWithAnUnknownStartIsNotAnalyzed() throws IOException { + assertThat(this.analyzer.analyze(new BeanCurrentlyInCreationException("test"))) + .isNull(); + } + private List readDescriptionLines(FailureAnalysis analysis) throws IOException { BufferedReader lineReader = new BufferedReader(