Skip to content

Commit b4c75ad

Browse files
committed
Merge pull request #22710 from dreis2211
* gh-22710: Introduce @ForkedClassPath for testing unmodified class path Closes gh-22710
2 parents 0158213 + c00d5c5 commit b4c75ad

File tree

5 files changed

+94
-12
lines changed

5 files changed

+94
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.classpath;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.junit.jupiter.api.extension.ExtendWith;
26+
27+
/**
28+
* Annotation used to fork the classpath. This can be helpful were neither
29+
* {@link ClassPathExclusions} or {@link ClassPathOverrides} are needed, but just a copy
30+
* of the classpath.
31+
*
32+
* @author Christoph Dreis
33+
* @since 2.4.0
34+
*/
35+
@Retention(RetentionPolicy.RUNTIME)
36+
@Target(ElementType.TYPE)
37+
@Documented
38+
@ExtendWith(ModifiedClassPathExtension.class)
39+
public @interface ForkedClassPath {
40+
41+
}

spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,14 @@ static ModifiedClassPathClassLoader get(Class<?> testClass) {
8989

9090
private static ModifiedClassPathClassLoader compute(Class<?> testClass) {
9191
ClassLoader classLoader = testClass.getClassLoader();
92-
return new ModifiedClassPathClassLoader(processUrls(extractUrls(classLoader), testClass),
92+
MergedAnnotations annotations = MergedAnnotations.from(testClass,
93+
MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
94+
if (annotations.isPresent(ForkedClassPath.class) && (annotations.isPresent(ClassPathOverrides.class)
95+
|| annotations.isPresent(ClassPathExclusions.class))) {
96+
throw new IllegalStateException("@ForkedClassPath is redundant in combination with either "
97+
+ "@ClassPathOverrides or @ClassPathExclusions");
98+
}
99+
return new ModifiedClassPathClassLoader(processUrls(extractUrls(classLoader), annotations),
93100
classLoader.getParent(), classLoader);
94101
}
95102

@@ -170,9 +177,7 @@ private static Attributes getManifestMainAttributesFromUrl(URL url) throws Excep
170177
}
171178
}
172179

173-
private static URL[] processUrls(URL[] urls, Class<?> testClass) {
174-
MergedAnnotations annotations = MergedAnnotations.from(testClass,
175-
MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
180+
private static URL[] processUrls(URL[] urls, MergedAnnotations annotations) {
176181
ClassPathEntryFilter filter = new ClassPathEntryFilter(annotations.get(ClassPathExclusions.class));
177182
List<URL> additionalUrls = getAdditionalUrls(annotations.get(ClassPathOverrides.class));
178183
List<URL> processedUrls = new ArrayList<>(additionalUrls);

spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtension.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@
3535
/**
3636
* A custom {@link Extension} that runs tests using a modified class path. Entries are
3737
* excluded from the class path using {@link ClassPathExclusions @ClassPathExclusions} and
38-
* overridden using {@link ClassPathOverrides @ClassPathOverrides} on the test class. A
39-
* class loader is created with the customized class path and is used both to load the
40-
* test class and as the thread context class loader while the test is being run.
38+
* overridden using {@link ClassPathOverrides @ClassPathOverrides} on the test class. For
39+
* an unchanged copy of the class path {@link ForkedClassPath @ForkedClassPath} can be
40+
* used. A class loader is created with the customized class path and is used both to load
41+
* the test class and as the thread context class loader while the test is being run.
4142
*
4243
* @author Christoph Dreis
43-
* @since 2.4.0
4444
*/
45-
public class ModifiedClassPathExtension implements InvocationInterceptor {
45+
class ModifiedClassPathExtension implements InvocationInterceptor {
4646

4747
@Override
4848
public void interceptBeforeAllMethod(Invocation<Void> invocation,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.classpath;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
/**
24+
* Tests for {@link ForkedClassPath @ForkedClassPath}.
25+
*
26+
* @author Christoph Dreis
27+
*/
28+
@ForkedClassPath
29+
class ModifiedClassPathExtensionForkTests {
30+
31+
@Test
32+
void modifiedClassLoaderIsUsed() {
33+
ClassLoader classLoader = getClass().getClassLoader();
34+
assertThat(classLoader.getClass().getName()).isEqualTo(ModifiedClassPathClassLoader.class.getName());
35+
}
36+
37+
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/IgnoringXmlBeanDefinitionLoaderTests.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919
import org.junit.jupiter.api.AfterAll;
2020
import org.junit.jupiter.api.BeforeAll;
2121
import org.junit.jupiter.api.Test;
22-
import org.junit.jupiter.api.extension.ExtendWith;
2322

2423
import org.springframework.beans.factory.BeanDefinitionStoreException;
25-
import org.springframework.boot.testsupport.classpath.ModifiedClassPathExtension;
24+
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
2625
import org.springframework.context.support.StaticApplicationContext;
2726

2827
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
2928

30-
@ExtendWith(ModifiedClassPathExtension.class)
29+
@ForkedClassPath
3130
class IgnoringXmlBeanDefinitionLoaderTests {
3231

3332
@BeforeAll

0 commit comments

Comments
 (0)