Add @AutoConfigureBefore and simple implementation
[#54597932] [bs-273] Circular view reference for /error
This commit is contained in:
parent
91a56f7bb7
commit
33658c2933
|
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -52,6 +53,7 @@ class AutoConfigurationSorter {
|
|||
|
||||
public List<String> getInPriorityOrder(Collection<String> classNames)
|
||||
throws IOException {
|
||||
|
||||
List<AutoConfigurationClass> autoConfigurationClasses = new ArrayList<AutoConfigurationClass>();
|
||||
for (String className : classNames) {
|
||||
autoConfigurationClasses.add(new AutoConfigurationClass(className));
|
||||
|
|
@ -65,30 +67,52 @@ class AutoConfigurationSorter {
|
|||
|
||||
List<String> orderedClassNames = new ArrayList<String>();
|
||||
for (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses) {
|
||||
orderedClassNames.add(autoConfigurationClass.toString());
|
||||
orderedClassNames.add(autoConfigurationClass.getClassName());
|
||||
}
|
||||
return orderedClassNames;
|
||||
|
||||
}
|
||||
|
||||
private List<AutoConfigurationClass> sortByAfterAnnotation(
|
||||
Collection<AutoConfigurationClass> autoConfigurationClasses)
|
||||
throws IOException {
|
||||
List<AutoConfigurationClass> tosort = new ArrayList<AutoConfigurationClass>(
|
||||
autoConfigurationClasses);
|
||||
|
||||
// Create a look up table of actual autoconfigs
|
||||
Map<AutoConfigurationClass, AutoConfigurationClass> tosort = new LinkedHashMap<AutoConfigurationClass, AutoConfigurationClass>();
|
||||
for (AutoConfigurationClass current : autoConfigurationClasses) {
|
||||
tosort.put(current, current);
|
||||
}
|
||||
addAftersFromBefores(tosort);
|
||||
|
||||
Set<AutoConfigurationClass> sorted = new LinkedHashSet<AutoConfigurationClass>();
|
||||
Set<AutoConfigurationClass> processing = new LinkedHashSet<AutoConfigurationClass>();
|
||||
while (!tosort.isEmpty()) {
|
||||
doSortByAfterAnnotation(tosort, sorted, processing, null);
|
||||
}
|
||||
|
||||
return new ArrayList<AutoConfigurationClass>(sorted);
|
||||
|
||||
}
|
||||
|
||||
private void doSortByAfterAnnotation(List<AutoConfigurationClass> tosort,
|
||||
private void addAftersFromBefores(
|
||||
Map<AutoConfigurationClass, AutoConfigurationClass> map) throws IOException {
|
||||
// Pick up any befores and add them to the corresponding after
|
||||
for (AutoConfigurationClass current : map.keySet()) {
|
||||
for (AutoConfigurationClass before : current.getBefore()) {
|
||||
if (map.containsKey(before)) {
|
||||
map.get(before).getAfter().add(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doSortByAfterAnnotation(
|
||||
Map<AutoConfigurationClass, AutoConfigurationClass> tosort,
|
||||
Set<AutoConfigurationClass> sorted, Set<AutoConfigurationClass> processing,
|
||||
AutoConfigurationClass current) throws IOException {
|
||||
|
||||
if (current == null) {
|
||||
current = tosort.remove(0);
|
||||
current = tosort.remove(tosort.keySet().iterator().next());
|
||||
}
|
||||
|
||||
processing.add(current);
|
||||
|
|
@ -97,8 +121,8 @@ class AutoConfigurationSorter {
|
|||
Assert.state(!processing.contains(after),
|
||||
"Cycle @AutoConfigureAfter detected between " + current + " and "
|
||||
+ after);
|
||||
if (!sorted.contains(after) && tosort.contains(after)) {
|
||||
doSortByAfterAnnotation(tosort, sorted, processing, after);
|
||||
if (!sorted.contains(after) && tosort.containsKey(after)) {
|
||||
doSortByAfterAnnotation(tosort, sorted, processing, tosort.get(after));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,12 +134,16 @@ class AutoConfigurationSorter {
|
|||
|
||||
private final String className;
|
||||
|
||||
private final int order;
|
||||
private int order;
|
||||
|
||||
private List<AutoConfigurationClass> after;
|
||||
|
||||
private List<AutoConfigurationClass> before;
|
||||
|
||||
private Map<String, Object> afterAnnotation;
|
||||
|
||||
private Map<String, Object> beforeAnnotation;
|
||||
|
||||
public AutoConfigurationClass(String className) throws IOException {
|
||||
|
||||
this.className = className;
|
||||
|
|
@ -127,12 +155,15 @@ class AutoConfigurationSorter {
|
|||
// Read @Order annotation
|
||||
Map<String, Object> orderedAnnotation = metadata
|
||||
.getAnnotationAttributes(Order.class.getName());
|
||||
this.order = (orderedAnnotation == null ? Ordered.LOWEST_PRECEDENCE
|
||||
: (Integer) orderedAnnotation.get("value"));
|
||||
this.order = (orderedAnnotation == null ? 0 : (Integer) orderedAnnotation
|
||||
.get("value"));
|
||||
|
||||
// Read @AutoConfigureAfter annotation
|
||||
this.afterAnnotation = metadata.getAnnotationAttributes(
|
||||
AutoConfigureAfter.class.getName(), true);
|
||||
// Read @AutoConfigureBefore annotation
|
||||
this.beforeAnnotation = metadata.getAnnotationAttributes(
|
||||
AutoConfigureBefore.class.getName(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -140,10 +171,14 @@ class AutoConfigurationSorter {
|
|||
return this.order;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return this.className;
|
||||
}
|
||||
|
||||
public List<AutoConfigurationClass> getAfter() throws IOException {
|
||||
if (this.after == null) {
|
||||
if (this.afterAnnotation == null) {
|
||||
this.after = Collections.emptyList();
|
||||
this.after = new ArrayList<AutoConfigurationClass>();
|
||||
}
|
||||
else {
|
||||
this.after = new ArrayList<AutoConfigurationClass>();
|
||||
|
|
@ -155,6 +190,22 @@ class AutoConfigurationSorter {
|
|||
return this.after;
|
||||
}
|
||||
|
||||
public List<AutoConfigurationClass> getBefore() throws IOException {
|
||||
if (this.before == null) {
|
||||
if (this.beforeAnnotation == null) {
|
||||
this.before = Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
this.before = new ArrayList<AutoConfigurationClass>();
|
||||
for (String beforeClass : (String[]) this.beforeAnnotation
|
||||
.get("value")) {
|
||||
this.before.add(new AutoConfigurationClass(beforeClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.before;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.className;
|
||||
|
|
@ -169,6 +220,7 @@ class AutoConfigurationSorter {
|
|||
public boolean equals(Object obj) {
|
||||
return this.className.equals(((AutoConfigurationClass) obj).className);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2012-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Hint for that an {@link EnableAutoConfiguration auto-configuration} should be applied
|
||||
* after the specified auto-configuration classes.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface AutoConfigureBefore {
|
||||
Class<?>[] value();
|
||||
}
|
||||
|
|
@ -16,20 +16,21 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.core.IsEqual;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationSorter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
|
|
@ -37,7 +38,7 @@ import static org.junit.Assert.assertThat;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AutoConfigurationSorterTest {
|
||||
public class AutoConfigurationSorterTests {
|
||||
|
||||
private static final String LOWEST = OrderLowest.class.getName();
|
||||
private static final String HIGHEST = OrderHighest.class.getName();
|
||||
|
|
@ -45,6 +46,11 @@ public class AutoConfigurationSorterTest {
|
|||
private static final String B = AutoConfigureB.class.getName();
|
||||
private static final String C = AutoConfigureC.class.getName();
|
||||
private static final String D = AutoConfigureD.class.getName();
|
||||
private static final String E = AutoConfigureE.class.getName();
|
||||
private static final String W = AutoConfigureW.class.getName();
|
||||
private static final String X = AutoConfigureX.class.getName();
|
||||
private static final String Y = AutoConfigureY.class.getName();
|
||||
private static final String Z = AutoConfigureZ.class.getName();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
|
@ -60,19 +66,38 @@ public class AutoConfigurationSorterTest {
|
|||
public void byOrderAnnotation() throws Exception {
|
||||
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(LOWEST,
|
||||
HIGHEST));
|
||||
assertThat(actual, equalTo(Arrays.asList(HIGHEST, LOWEST)));
|
||||
assertThat(actual, nameMatcher(HIGHEST, LOWEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byAutoConfigureAfter() throws Exception {
|
||||
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B, C));
|
||||
assertThat(actual, equalTo(Arrays.asList(C, B, A)));
|
||||
assertThat(actual, nameMatcher(C, B, A));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byAutoConfigureBefore() throws Exception {
|
||||
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(X, Y, Z));
|
||||
assertThat(actual, nameMatcher(Z, Y, X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byAutoConfigureAfterDoubles() throws Exception {
|
||||
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, E));
|
||||
assertThat(actual, nameMatcher(C, E, B, A));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byAutoConfigureMixedBeforeAndAfter() throws Exception {
|
||||
List<String> actual = this.sorter
|
||||
.getInPriorityOrder(Arrays.asList(A, B, C, W, X));
|
||||
assertThat(actual, nameMatcher(C, W, B, A, X));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byAutoConfigureAfterWithMissing() throws Exception {
|
||||
List<String> actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B));
|
||||
assertThat(actual, equalTo(Arrays.asList(B, A)));
|
||||
assertThat(actual, nameMatcher(B, A));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -82,6 +107,39 @@ public class AutoConfigurationSorterTest {
|
|||
this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, D));
|
||||
}
|
||||
|
||||
private Matcher<? super List<String>> nameMatcher(String... names) {
|
||||
|
||||
final List<String> list = Arrays.asList(names);
|
||||
|
||||
return new IsEqual<List<String>>(list) {
|
||||
|
||||
@Override
|
||||
public void describeMismatch(Object item, Description description) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> items = (List<String>) item;
|
||||
description.appendText("was ").appendValue(prettify(items));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(prettify(list));
|
||||
}
|
||||
|
||||
private String prettify(List<String> items) {
|
||||
List<String> pretty = new ArrayList<String>();
|
||||
for (String item : items) {
|
||||
if (item.contains("$AutoConfigure")) {
|
||||
item = item.substring(item.indexOf("$AutoConfigure")
|
||||
+ "$AutoConfigure".length());
|
||||
}
|
||||
pretty.add(item);
|
||||
}
|
||||
return pretty.toString();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
public static class OrderLowest {
|
||||
}
|
||||
|
|
@ -94,7 +152,8 @@ public class AutoConfigurationSorterTest {
|
|||
public static class AutoConfigureA {
|
||||
}
|
||||
|
||||
@AutoConfigureAfter({ AutoConfigureC.class, AutoConfigureD.class })
|
||||
@AutoConfigureAfter({ AutoConfigureC.class, AutoConfigureD.class,
|
||||
AutoConfigureE.class })
|
||||
public static class AutoConfigureB {
|
||||
}
|
||||
|
||||
|
|
@ -104,4 +163,23 @@ public class AutoConfigurationSorterTest {
|
|||
@AutoConfigureAfter(AutoConfigureA.class)
|
||||
public static class AutoConfigureD {
|
||||
}
|
||||
|
||||
public static class AutoConfigureE {
|
||||
}
|
||||
|
||||
@AutoConfigureBefore(AutoConfigureB.class)
|
||||
public static class AutoConfigureW {
|
||||
}
|
||||
|
||||
public static class AutoConfigureX {
|
||||
}
|
||||
|
||||
@AutoConfigureBefore(AutoConfigureX.class)
|
||||
public static class AutoConfigureY {
|
||||
}
|
||||
|
||||
@AutoConfigureBefore(AutoConfigureY.class)
|
||||
public static class AutoConfigureZ {
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue