mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Additional fixes for auto-configuration report
Fix the following issues that were introduced in commit 0610378
:
- Formatting of code including imports
- Improve hashcode/equals implementations by using ObjectUtils
- Provide hashcode/equals for ConditionOutcome
- Use LinkedHashSet in ConditionAndOutcomes to maintain insert order
Fixed gh-127
This commit is contained in:
parent
b5b86d07ba
commit
751beda2cb
@ -16,13 +16,21 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Records auto-configuration details for reporting and logging.
|
||||
@ -34,7 +42,9 @@ import org.springframework.context.annotation.Condition;
|
||||
public class AutoConfigurationReport {
|
||||
|
||||
private static final String BEAN_NAME = "autoConfigurationReport";
|
||||
|
||||
private final SortedMap<String, ConditionAndOutcomes> outcomes = new TreeMap<String, ConditionAndOutcomes>();
|
||||
|
||||
private AutoConfigurationReport parent;
|
||||
|
||||
/**
|
||||
@ -52,6 +62,9 @@ public class AutoConfigurationReport {
|
||||
*/
|
||||
public void recordConditionEvaluation(String source, Condition condition,
|
||||
ConditionOutcome outcome) {
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
Assert.notNull(condition, "Condition must not be null");
|
||||
Assert.notNull(outcome, "Outcome must not be null");
|
||||
if (!this.outcomes.containsKey(source)) {
|
||||
this.outcomes.put(source, new ConditionAndOutcomes());
|
||||
}
|
||||
@ -67,7 +80,6 @@ public class AutoConfigurationReport {
|
||||
|
||||
/**
|
||||
* The parent report (from a parent BeanFactory if there is one).
|
||||
*
|
||||
* @return the parent report (or null if there isn't one)
|
||||
*/
|
||||
public AutoConfigurationReport getParent() {
|
||||
@ -107,7 +119,7 @@ public class AutoConfigurationReport {
|
||||
*/
|
||||
public static class ConditionAndOutcomes implements Iterable<ConditionAndOutcome> {
|
||||
|
||||
private Set<ConditionAndOutcome> outcomes = new HashSet<ConditionAndOutcome>();
|
||||
private Set<ConditionAndOutcome> outcomes = new LinkedHashSet<ConditionAndOutcome>();
|
||||
|
||||
public void add(Condition condition, ConditionOutcome outcome) {
|
||||
this.outcomes.add(new ConditionAndOutcome(condition, outcome));
|
||||
@ -138,6 +150,7 @@ public class AutoConfigurationReport {
|
||||
public static class ConditionAndOutcome {
|
||||
|
||||
private final Condition condition;
|
||||
|
||||
private final ConditionOutcome outcome;
|
||||
|
||||
public ConditionAndOutcome(Condition condition, ConditionOutcome outcome) {
|
||||
@ -154,29 +167,23 @@ public class AutoConfigurationReport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
if (this.outcome == null || this.outcome.getMessage() == null) {
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConditionAndOutcome that = (ConditionAndOutcome) o;
|
||||
|
||||
if (that.getOutcome() == null || this.getOutcome().getMessage() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getOutcome().getMessage().equals(that.getOutcome().getMessage());
|
||||
ConditionAndOutcome other = (ConditionAndOutcome) obj;
|
||||
return (ObjectUtils.nullSafeEquals(this.condition.getClass(),
|
||||
other.condition.getClass()) && ObjectUtils.nullSafeEquals(
|
||||
this.outcome, other.outcome));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return outcome != null && outcome.getMessage() != null ? outcome.getMessage().hashCode() : 0;
|
||||
return this.condition.getClass().hashCode() * 31 + this.outcome.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Outcome for a condition match, including log message.
|
||||
*
|
||||
@ -69,4 +71,26 @@ public class ConditionOutcome {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.hashCode(this.match) * 31
|
||||
+ ObjectUtils.nullSafeHashCode(this.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() == obj.getClass()) {
|
||||
ConditionOutcome other = (ConditionOutcome) obj;
|
||||
return (this.match == other.match && ObjectUtils.nullSafeEquals(this.message,
|
||||
other.message));
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
@ -37,13 +38,13 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AutoConfigurationReport}.
|
||||
@ -66,13 +67,10 @@ public class AutoConfigurationReportTests {
|
||||
@Mock
|
||||
private Condition condition3;
|
||||
|
||||
@Mock
|
||||
private ConditionOutcome outcome1;
|
||||
|
||||
@Mock
|
||||
private ConditionOutcome outcome2;
|
||||
|
||||
@Mock
|
||||
private ConditionOutcome outcome3;
|
||||
|
||||
@Before
|
||||
@ -92,7 +90,8 @@ public class AutoConfigurationReportTests {
|
||||
@Test
|
||||
public void parent() throws Exception {
|
||||
this.beanFactory.setParentBeanFactory(new DefaultListableBeanFactory());
|
||||
AutoConfigurationReport.get((ConfigurableListableBeanFactory) this.beanFactory.getParentBeanFactory());
|
||||
AutoConfigurationReport.get((ConfigurableListableBeanFactory) this.beanFactory
|
||||
.getParentBeanFactory());
|
||||
assertThat(this.report,
|
||||
sameInstance(AutoConfigurationReport.get(this.beanFactory)));
|
||||
assertThat(this.report, not(nullValue()));
|
||||
@ -101,24 +100,26 @@ public class AutoConfigurationReportTests {
|
||||
|
||||
@Test
|
||||
public void recordConditionEvaluations() throws Exception {
|
||||
given(this.outcome1.getMessage()).willReturn("Message 1");
|
||||
given(this.outcome2.getMessage()).willReturn("Message 2");
|
||||
given(this.outcome3.getMessage()).willReturn("Message 3");
|
||||
|
||||
this.outcome1 = new ConditionOutcome(false, "m1");
|
||||
this.outcome2 = new ConditionOutcome(false, "m2");
|
||||
this.outcome3 = new ConditionOutcome(false, "m3");
|
||||
this.report.recordConditionEvaluation("a", this.condition1, this.outcome1);
|
||||
this.report.recordConditionEvaluation("a", this.condition2, this.outcome2);
|
||||
this.report.recordConditionEvaluation("b", this.condition3, this.outcome3);
|
||||
|
||||
Map<String, ConditionAndOutcomes> map = this.report.getConditionAndOutcomesBySource();
|
||||
Map<String, ConditionAndOutcomes> map = this.report
|
||||
.getConditionAndOutcomesBySource();
|
||||
assertThat(map.size(), equalTo(2));
|
||||
Iterator<ConditionAndOutcome> iterator = map.get("a").iterator();
|
||||
|
||||
ConditionAndOutcome conditionAndOutcome = iterator.next();
|
||||
assertThat(conditionAndOutcome.getCondition(), equalTo(this.condition1));
|
||||
assertThat(conditionAndOutcome.getOutcome(), equalTo(this.outcome1));
|
||||
|
||||
conditionAndOutcome = iterator.next();
|
||||
assertThat(conditionAndOutcome.getCondition(), equalTo(this.condition2));
|
||||
assertThat(conditionAndOutcome.getOutcome(), equalTo(this.outcome2));
|
||||
assertThat(iterator.hasNext(), equalTo(false));
|
||||
|
||||
iterator = map.get("b").iterator();
|
||||
conditionAndOutcome = iterator.next();
|
||||
assertThat(conditionAndOutcome.getCondition(), equalTo(this.condition3));
|
||||
@ -141,9 +142,9 @@ public class AutoConfigurationReportTests {
|
||||
}
|
||||
|
||||
private void prepareMatches(boolean m1, boolean m2, boolean m3) {
|
||||
given(this.outcome1.isMatch()).willReturn(m1);
|
||||
given(this.outcome2.isMatch()).willReturn(m2);
|
||||
given(this.outcome3.isMatch()).willReturn(m3);
|
||||
this.outcome1 = new ConditionOutcome(m1, "m1");
|
||||
this.outcome2 = new ConditionOutcome(m2, "m2");
|
||||
this.outcome3 = new ConditionOutcome(m3, "m3");
|
||||
this.report.recordConditionEvaluation("a", this.condition1, this.outcome1);
|
||||
this.report.recordConditionEvaluation("a", this.condition2, this.outcome2);
|
||||
this.report.recordConditionEvaluation("a", this.condition3, this.outcome3);
|
||||
@ -152,90 +153,69 @@ public class AutoConfigurationReportTests {
|
||||
@Test
|
||||
@SuppressWarnings("resource")
|
||||
public void springBootConditionPopulatesReport() throws Exception {
|
||||
AutoConfigurationReport report = AutoConfigurationReport.get(new AnnotationConfigApplicationContext(
|
||||
Config.class).getBeanFactory());
|
||||
AutoConfigurationReport report = AutoConfigurationReport
|
||||
.get(new AnnotationConfigApplicationContext(Config.class)
|
||||
.getBeanFactory());
|
||||
assertThat(report.getConditionAndOutcomesBySource().size(), not(equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateConditionAndOutcomes() {
|
||||
Condition condition1 = mock(Condition.class);
|
||||
ConditionOutcome conditionOutcome1 = mock(ConditionOutcome.class);
|
||||
given(conditionOutcome1.getMessage()).willReturn("This is message 1");
|
||||
ConditionAndOutcome outcome1 = new ConditionAndOutcome(this.condition1,
|
||||
new ConditionOutcome(true, "Message 1"));
|
||||
ConditionAndOutcome outcome2 = new ConditionAndOutcome(this.condition2,
|
||||
new ConditionOutcome(true, "Message 2"));
|
||||
ConditionAndOutcome outcome3 = new ConditionAndOutcome(this.condition3,
|
||||
new ConditionOutcome(true, "Message 2"));
|
||||
|
||||
Condition condition2 = mock(Condition.class);
|
||||
ConditionOutcome conditionOutcome2 = mock(ConditionOutcome.class);
|
||||
given(conditionOutcome2.getMessage()).willReturn("This is message 2");
|
||||
|
||||
Condition condition3 = mock(Condition.class);
|
||||
ConditionOutcome conditionOutcome3 = mock(ConditionOutcome.class);
|
||||
given(conditionOutcome3.getMessage()).willReturn("This is message 2"); // identical in value to #2
|
||||
|
||||
ConditionAndOutcome outcome1 = new ConditionAndOutcome(condition1,
|
||||
conditionOutcome1);
|
||||
assertThat(outcome1, equalTo(outcome1));
|
||||
|
||||
ConditionAndOutcome outcome2 = new ConditionAndOutcome(condition2,
|
||||
conditionOutcome2);
|
||||
assertThat(outcome1, not(equalTo(outcome2)));
|
||||
|
||||
ConditionAndOutcome outcome3 = new ConditionAndOutcome(condition3,
|
||||
conditionOutcome3);
|
||||
assertThat(outcome2, equalTo(outcome3));
|
||||
|
||||
Set<ConditionAndOutcome> set = new HashSet<ConditionAndOutcome>();
|
||||
set.add(outcome1);
|
||||
set.add(outcome2);
|
||||
set.add(outcome3);
|
||||
assertThat(set.size(), equalTo(2));
|
||||
|
||||
ConditionAndOutcomes outcomes = new ConditionAndOutcomes();
|
||||
outcomes.add(condition1, conditionOutcome1);
|
||||
outcomes.add(condition2, conditionOutcome2);
|
||||
outcomes.add(condition3, conditionOutcome3);
|
||||
outcomes.add(this.condition1, new ConditionOutcome(true, "Message 1"));
|
||||
outcomes.add(this.condition2, new ConditionOutcome(true, "Message 2"));
|
||||
outcomes.add(this.condition3, new ConditionOutcome(true, "Message 2"));
|
||||
|
||||
int i = 0;
|
||||
Iterator<ConditionAndOutcome> iterator = outcomes.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
i++;
|
||||
iterator.next();
|
||||
}
|
||||
assertThat(i, equalTo(2));
|
||||
assertThat(getNumberOfOutcomes(outcomes), equalTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void duplicateOutcomes() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
DuplicateConfig.class);
|
||||
AutoConfigurationReport report = AutoConfigurationReport.get(context.getBeanFactory());
|
||||
String autoconfigKey = "org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration";
|
||||
AutoConfigurationReport report = AutoConfigurationReport.get(context
|
||||
.getBeanFactory());
|
||||
String autoconfigKey = MultipartAutoConfiguration.class.getName();
|
||||
|
||||
assertThat(report.getConditionAndOutcomesBySource().keySet(),
|
||||
hasItem(autoconfigKey));
|
||||
|
||||
ConditionAndOutcomes conditionAndOutcomes = report.getConditionAndOutcomesBySource().get(
|
||||
ConditionAndOutcomes outcomes = report.getConditionAndOutcomesBySource().get(
|
||||
autoconfigKey);
|
||||
Iterator<ConditionAndOutcome> iterator = conditionAndOutcomes.iterator();
|
||||
int i = 0;
|
||||
boolean foundConditionalOnClass = false;
|
||||
boolean foundConditionalOnBean = false;
|
||||
while (iterator.hasNext()) {
|
||||
ConditionAndOutcome conditionAndOutcome = iterator.next();
|
||||
if (conditionAndOutcome.getOutcome().getMessage().contains(
|
||||
"@ConditionalOnClass classes found: javax.servlet.Servlet,org.springframework.web.multipart.support.StandardServletMultipartResolver")) {
|
||||
foundConditionalOnClass = true;
|
||||
}
|
||||
if (conditionAndOutcome.getOutcome().getMessage().contains(
|
||||
"@ConditionalOnBean (types: javax.servlet.MultipartConfigElement; SearchStrategy: all) found no beans")) {
|
||||
foundConditionalOnBean = true;
|
||||
}
|
||||
i++;
|
||||
assertThat(outcomes, not(nullValue()));
|
||||
assertThat(getNumberOfOutcomes(outcomes), equalTo(2));
|
||||
|
||||
List<String> messages = new ArrayList<String>();
|
||||
for (ConditionAndOutcome outcome : outcomes) {
|
||||
messages.add(outcome.getOutcome().getMessage());
|
||||
System.out.println(outcome.getOutcome().getMessage());
|
||||
}
|
||||
|
||||
assertThat(i, equalTo(2));
|
||||
assertTrue(foundConditionalOnClass);
|
||||
assertTrue(foundConditionalOnBean);
|
||||
Matcher<String> onClassMessage = containsString("@ConditionalOnClass "
|
||||
+ "classes found: javax.servlet.Servlet,org.springframework.web.multipart.support.StandardServletMultipartResolver");
|
||||
Matcher<String> onBeanMessage = containsString("@ConditionalOnBean "
|
||||
+ "(types: javax.servlet.MultipartConfigElement; SearchStrategy: all) found no beans");
|
||||
assertThat(messages, containsInAnyOrder(onClassMessage, onBeanMessage));
|
||||
context.close();
|
||||
}
|
||||
|
||||
private int getNumberOfOutcomes(ConditionAndOutcomes outcomes) {
|
||||
Iterator<ConditionAndOutcome> iterator = outcomes.iterator();
|
||||
int numberOfOutcomesAdded = 0;
|
||||
while (iterator.hasNext()) {
|
||||
numberOfOutcomesAdded++;
|
||||
iterator.next();
|
||||
}
|
||||
return numberOfOutcomesAdded;
|
||||
}
|
||||
|
||||
@Configurable
|
||||
|
Loading…
Reference in New Issue
Block a user