Skip to content

Commit bbafe10

Browse files
committed
Create specialized sub-interface of Extension
This enforces that only potentially affected extensions can override the method determining the extension context scope during test class instance construction.
1 parent 6b80f42 commit bbafe10

File tree

17 files changed

+175
-146
lines changed

17 files changed

+175
-146
lines changed

documentation/src/docs/asciidoc/link-attributes.adoc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ endif::[]
142142
:ExecutableInvoker: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutableInvoker.html[ExecutableInvoker]
143143
:ExecutionCondition: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExecutionCondition.html[ExecutionCondition]
144144
:ExtendWith: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtendWith.html[@ExtendWith]
145-
:Extension: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/Extension.html[Extension]
146145
:ExtensionContext: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.html[ExtensionContext]
147146
:ExtensionContext_Store: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/ExtensionContext.Store.html[Store]
148147
:InvocationInterceptor: {javadoc-root}/org.junit.jupiter.api/org/junit/jupiter/api/extension/InvocationInterceptor.html[InvocationInterceptor]

documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ JUnit repository on GitHub.
5858
extensions.
5959
* Allow determining "shared resources" at runtime via the new `@ResourceLock#providers`
6060
attribute that accepts implementations of `ResourceLocksProvider`.
61-
* Overriding `Extension.getExtensionContextScopeDuringTestInstanceConstruction()` enables
62-
using a test-scoped `ExtensionContext` in `Extension` methods called during test class
61+
* Extensions that participate in the construction of test class instances may override the
62+
`getExtensionContextScopeDuringTestClassInstanceConstruction()` method to enable using a
63+
test-scoped `ExtensionContext` in `Extension` methods called during test class instance
6364
construction. This behavior will become the default in future versions of JUnit.
6465
* `@TempDir` is now supported on test class constructors.
6566

documentation/src/docs/asciidoc/user-guide/extensions.adoc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ instances and their lifecycle.
384384
[NOTE]
385385
====
386386
You may override the
387-
`{Extension}.getExtensionContextScopeDuringTestInstanceConstruction(...)` method to return
387+
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
388388
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
389389
available to your implementation.
390390
====
@@ -418,7 +418,7 @@ registered for any specific test class.
418418
[NOTE]
419419
====
420420
You may override the
421-
`{Extension}.getExtensionContextScopeDuringTestInstanceConstruction(...)` method to return
421+
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
422422
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
423423
available to your implementation.
424424
====
@@ -438,7 +438,7 @@ For a concrete example, consult the source code for the `{MockitoExtension}` and
438438
[NOTE]
439439
====
440440
You may override the
441-
`{Extension}.getExtensionContextScopeDuringTestInstanceConstruction(...)` method to return
441+
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
442442
`TEST_SCOPED` for revised handling of `CloseableResource` and to make test-specific data
443443
available to your implementation.
444444
====
@@ -492,9 +492,9 @@ those provided in `java.lang.reflect.Parameter` in order to avoid this bug in th
492492
[NOTE]
493493
====
494494
You may override the
495-
`{Extension}.getExtensionContextScopeDuringTestInstanceConstruction(...)` method to return
495+
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
496496
`TEST_SCOPED` to support injecting test specific data into constructor parameters of the
497-
test instance. Doing so causes a test-specific `{ExtensionContext}` to be used while
497+
test class instance. Doing so causes a test-specific `{ExtensionContext}` to be used while
498498
resolving constructor parameters, unless the
499499
<<writing-tests-test-instance-lifecycle, test instance lifecycle>> is set to `PER_CLASS`.
500500
====
@@ -732,7 +732,7 @@ include::{testDir}/example/interceptor/SwingEdtInterceptor.java[tags=user_guide]
732732
[NOTE]
733733
====
734734
You may override the
735-
`{Extension}.getExtensionContextScopeDuringTestInstanceConstruction(...)` method to return
735+
`getExtensionContextScopeDuringTestClassInstanceConstruction(...)` method to return
736736
`TEST_SCOPED` to make test-specific data available to your implementation of
737737
`interceptTestClassConstructor` and for a revised scope of the provided `Store` instance.
738738
====

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extension.java

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,9 @@
1010

1111
package org.junit.jupiter.api.extension;
1212

13-
import static org.apiguardian.api.API.Status.DEPRECATED;
14-
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
1513
import static org.apiguardian.api.API.Status.STABLE;
1614

1715
import org.apiguardian.api.API;
18-
import org.junit.jupiter.api.TestInstance;
19-
import org.junit.jupiter.api.extension.ExtensionContext.Store;
20-
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;
2116

2217
/**
2318
* Marker interface for all extensions.
@@ -43,97 +38,4 @@
4338
*/
4439
@API(status = STABLE, since = "5.0")
4540
public interface Extension {
46-
47-
/**
48-
* Whether this extension should receive a test-scoped
49-
* {@link ExtensionContext} during the creation of test instances.
50-
*
51-
* <p>If an extension returns
52-
* {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED} from this method,
53-
* the following extension methods will be called with a test-scoped
54-
* {@link ExtensionContext} instead of a class-scoped one, unless the
55-
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used:
56-
*
57-
* <ul>
58-
* <li>{@link InvocationInterceptor#interceptTestClassConstructor}</li>
59-
* <li>{@link ParameterResolver} when resolving constructor parameters</li>
60-
* <li>{@link TestInstancePreConstructCallback}</li>
61-
* <li>{@link TestInstancePostProcessor}</li>
62-
* <li>{@link TestInstanceFactory}</li>
63-
* </ul>
64-
*
65-
* <p>In such cases, implementations of these extension callbacks can
66-
* observe the following differences:
67-
*
68-
* <ul>
69-
* <li>{@link ExtensionContext#getElement() getElement()} may refer to the
70-
* test method and {@link ExtensionContext#getTestClass() getTestClass()}
71-
* may refer to a nested test class.
72-
* Use {@link TestInstanceFactoryContext#getTestClass()} to get the class
73-
* under construction.</li>
74-
* <li>{@link ExtensionContext#getTestMethod() getTestMethod()} is no-longer
75-
* empty, unless the test class is annotated with
76-
* {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
77-
* <li>If the callback adds a new {@link CloseableResource} to the
78-
* {@link Store}, the resource is closed just after the instance is
79-
* destroyed.</li>
80-
* <li>The callbacks can now access data previously stored by
81-
* {@link TestTemplateInvocationContext}, unless the test class is annotated
82-
* with {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
83-
* </ul>
84-
*
85-
* <p><strong>Note</strong>: The behavior which is enabled by returning
86-
* {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED} from this method
87-
* will become the default in future versions of JUnit. To ensure future
88-
* compatibility, extension implementors are therefore advised to opt in,
89-
* even if they don't require the new functionality.
90-
*
91-
* @implNote There are no guarantees about how often this method is called.
92-
* Therefore, implementations should be idempotent and avoid side
93-
* effects. They may, however, cache the result for performance in
94-
* the {@link Store Store} of the supplied
95-
* {@link ExtensionContext}, if necessary.
96-
* @param rootContext the root extension context to allow inspection of
97-
* configuration parameters; never {@code null}
98-
* @since 5.12
99-
* @see InvocationInterceptor#interceptTestClassConstructor
100-
* @see ParameterResolver
101-
* @see TestInstancePreConstructCallback
102-
* @see TestInstancePostProcessor
103-
* @see TestInstanceFactory
104-
*/
105-
@API(status = EXPERIMENTAL, since = "5.12")
106-
default ExtensionContextScope getExtensionContextScopeDuringTestInstanceConstruction(ExtensionContext rootContext) {
107-
return ExtensionContextScope.DEFAULT;
108-
}
109-
110-
/**
111-
* {@code ExtensionContextScope} is used to define the scope of the
112-
* {@link ExtensionContext} passed to an extension during the creation of
113-
* test instances.
114-
*
115-
* @since 5.12
116-
* @see org.junit.jupiter.api.extension.Extension#getExtensionContextScopeDuringTestInstanceConstruction
117-
*/
118-
@API(status = EXPERIMENTAL, since = "5.12")
119-
enum ExtensionContextScope {
120-
121-
/**
122-
* The extension should receive an {@link ExtensionContext} scoped to
123-
* the test class.
124-
*
125-
* @deprecated This behavior will be removed from future versions of
126-
* JUnit and {@link #TEST_SCOPED} will become the default.
127-
*/
128-
@API(status = DEPRECATED, since = "5.12") //
129-
@Deprecated
130-
DEFAULT,
131-
132-
/**
133-
* The extension should receive an {@link ExtensionContext} scoped to
134-
* the test instance.
135-
*/
136-
TEST_SCOPED
137-
}
138-
13941
}

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/InvocationInterceptor.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
* @see ExtensionContext
5252
*/
5353
@API(status = STABLE, since = "5.10")
54-
public interface InvocationInterceptor extends Extension {
54+
public interface InvocationInterceptor extends TestClassInstanceConstructionParticipatingExtension {
5555

5656
/**
5757
* Intercept the invocation of a test class constructor.
@@ -60,9 +60,9 @@ public interface InvocationInterceptor extends Extension {
6060
* (static initialization) when this method is invoked.
6161
*
6262
* <p>Extensions may override
63-
* {@link #getExtensionContextScopeDuringTestInstanceConstruction} to make
64-
* test-specific data available to the implementation of this method and for
65-
* a revised scope of the provided {@link Store} instance.
63+
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} to
64+
* make test-specific data available to the implementation of this method
65+
* and for a revised scope of the provided {@link Store Store} instance.
6666
*
6767
* @param invocation the invocation that is being intercepted; never
6868
* {@code null}

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/ParameterResolver.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@
3232
* {@code ParameterResolver}.
3333
*
3434
* <p>Extensions may override
35-
* {@link #getExtensionContextScopeDuringTestInstanceConstruction} to support
36-
* injecting test specific data into constructor parameters of the test
37-
* instance. Returning {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED}
38-
* from this method, causes a test-specific {@link ExtensionContext} to be used
39-
* while resolving constructor parameters, unless the lifecycle is set to
35+
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} to
36+
* support injecting test specific data into constructor parameters of the test
37+
* class instance. Returning
38+
* {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED} from this method,
39+
* causes a test-specific {@link ExtensionContext} to be used while resolving
40+
* constructor parameters, unless the lifecycle is set to
4041
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS}.
4142
*
4243
* <h2>Constructor Requirements</h2>
@@ -53,7 +54,7 @@
5354
* @see TestInstancePreDestroyCallback
5455
*/
5556
@API(status = STABLE, since = "5.0")
56-
public interface ParameterResolver extends Extension {
57+
public interface ParameterResolver extends TestClassInstanceConstructionParticipatingExtension {
5758

5859
/**
5960
* Determine if this resolver supports resolution of an argument for the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2015-2024 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.jupiter.api.extension;
12+
13+
import static org.apiguardian.api.API.Status.DEPRECATED;
14+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
15+
16+
import org.apiguardian.api.API;
17+
import org.junit.jupiter.api.TestInstance;
18+
19+
/**
20+
* Interface for {@link Extension Extensions} that participate in the
21+
* construction of test class instances.
22+
*
23+
* @since 5.12
24+
* @see InvocationInterceptor#interceptTestClassConstructor
25+
* @see ParameterResolver
26+
* @see TestInstancePreConstructCallback
27+
* @see TestInstancePostProcessor
28+
* @see TestInstanceFactory
29+
*/
30+
@API(status = EXPERIMENTAL, since = "5.12")
31+
public interface TestClassInstanceConstructionParticipatingExtension extends Extension {
32+
33+
/**
34+
* Whether this extension should receive a test-scoped
35+
* {@link ExtensionContext} during the creation of test instances.
36+
*
37+
* <p>If an extension returns
38+
* {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED} from this method,
39+
* the following extension methods will be called with a test-scoped
40+
* {@link ExtensionContext} instead of a class-scoped one, unless the
41+
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used:
42+
*
43+
* <ul>
44+
* <li>{@link InvocationInterceptor#interceptTestClassConstructor}</li>
45+
* <li>{@link ParameterResolver} when resolving constructor parameters</li>
46+
* <li>{@link TestInstancePreConstructCallback}</li>
47+
* <li>{@link TestInstancePostProcessor}</li>
48+
* <li>{@link TestInstanceFactory}</li>
49+
* </ul>
50+
*
51+
* <p>In such cases, implementations of these extension callbacks can
52+
* observe the following differences:
53+
*
54+
* <ul>
55+
* <li>{@link ExtensionContext#getElement() getElement()} may refer to the
56+
* test method and {@link ExtensionContext#getTestClass() getTestClass()}
57+
* may refer to a nested test class.
58+
* Use {@link TestInstanceFactoryContext#getTestClass()} to get the class
59+
* under construction.</li>
60+
* <li>{@link ExtensionContext#getTestMethod() getTestMethod()} is no-longer
61+
* empty, unless the test class is annotated with
62+
* {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
63+
* <li>If the callback adds a new {@link ExtensionContext.Store.CloseableResource} to the
64+
* {@link ExtensionContext.Store}, the resource is closed just after the instance is
65+
* destroyed.</li>
66+
* <li>The callbacks can now access data previously stored by
67+
* {@link TestTemplateInvocationContext}, unless the test class is annotated
68+
* with {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}.</li>
69+
* </ul>
70+
*
71+
* <p><strong>Note</strong>: The behavior which is enabled by returning
72+
* {@link ExtensionContextScope#TEST_SCOPED TEST_SCOPED} from this method
73+
* will become the default in future versions of JUnit. To ensure future
74+
* compatibility, extension implementors are therefore advised to opt in,
75+
* even if they don't require the new functionality.
76+
*
77+
* @implNote There are no guarantees about how often this method is called.
78+
* Therefore, implementations should be idempotent and avoid side
79+
* effects. They may, however, cache the result for performance in
80+
* the {@link ExtensionContext.Store Store} of the supplied
81+
* {@link ExtensionContext}, if necessary.
82+
* @param rootContext the root extension context to allow inspection of
83+
* configuration parameters; never {@code null}
84+
* @since 5.12
85+
*/
86+
@API(status = EXPERIMENTAL, since = "5.12")
87+
default ExtensionContextScope getExtensionContextScopeDuringTestClassInstanceConstruction(
88+
ExtensionContext rootContext) {
89+
return ExtensionContextScope.DEFAULT;
90+
}
91+
92+
/**
93+
* {@code ExtensionContextScope} is used to define the scope of the
94+
* {@link ExtensionContext} passed to an extension during the creation of
95+
* test instances.
96+
*
97+
* @since 5.12
98+
* @see TestClassInstanceConstructionParticipatingExtension#getExtensionContextScopeDuringTestClassInstanceConstruction
99+
*/
100+
@API(status = EXPERIMENTAL, since = "5.12")
101+
enum ExtensionContextScope {
102+
103+
/**
104+
* The extension should receive an {@link ExtensionContext} scoped to
105+
* the test class.
106+
*
107+
* @deprecated This behavior will be removed from future versions of
108+
* JUnit and {@link #TEST_SCOPED} will become the default.
109+
*/
110+
@API(status = DEPRECATED, since = "5.12") //
111+
@Deprecated
112+
DEFAULT,
113+
114+
/**
115+
* The extension should receive an {@link ExtensionContext} scoped to
116+
* the test instance.
117+
*/
118+
TEST_SCOPED
119+
}
120+
121+
}

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstanceFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@
5252
*/
5353
@FunctionalInterface
5454
@API(status = STABLE, since = "5.7")
55-
public interface TestInstanceFactory extends Extension {
55+
public interface TestInstanceFactory extends TestClassInstanceConstructionParticipatingExtension {
5656

5757
/**
5858
* Callback for creating a test instance for the supplied context.
5959
*
6060
* <p>Extensions may override
61-
* {@link #getExtensionContextScopeDuringTestInstanceConstruction} for
61+
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} for
6262
* revised handling of {@link CloseableResource CloseableResource} and to
6363
* make test-specific data available to your implementation.
6464
*

junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/TestInstancePostProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@
4141
*/
4242
@FunctionalInterface
4343
@API(status = STABLE, since = "5.0")
44-
public interface TestInstancePostProcessor extends Extension {
44+
public interface TestInstancePostProcessor extends TestClassInstanceConstructionParticipatingExtension {
4545

4646
/**
4747
* Callback for post-processing the supplied test instance.
4848
*
4949
* <p>Extensions may override
50-
* {@link #getExtensionContextScopeDuringTestInstanceConstruction} for
50+
* {@link #getExtensionContextScopeDuringTestClassInstanceConstruction} for
5151
* revised handling of {@link CloseableResource CloseableResource} and to
5252
* make test-specific data available to your implementation.
5353
*

0 commit comments

Comments
 (0)