forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce MethodInvoker API for TestExecutionListeners
In order to be able to support parameter injection in @BeforeTransaction and @AfterTransaction methods (see spring-projectsgh-30736), this commit introduces a MethodInvoker API for TestExecutionListeners as a generic mechanism for delegating to the underlying testing framework to invoke methods. The default implementation simply invokes the method without arguments, which allows TestExecutionListeners using this mechanism to operate correctly when the underlying testing framework is JUnit 4, TestNG, etc. A JUnit Jupiter specific implementation is registered in the SpringExtension which delegates to the ExtensionContext.getExecutableInvoker() mechanism introduced in JUnit Jupiter 5.9. This allows a TestExecutionListener to transparently benefit from registered ParameterResolvers in JUnit Jupiter (including the SpringExtension) when invoking user methods, effectively providing support for parameter injection for arbitrary methods. Closes spring-projectsgh-31199
- Loading branch information
Showing
7 changed files
with
328 additions
and
87 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
spring-test/src/main/java/org/springframework/test/context/DefaultMethodInvoker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 2002-2023 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 | ||
* | ||
* https://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.test.context; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
|
||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
|
||
import org.springframework.lang.Nullable; | ||
import org.springframework.util.Assert; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
/** | ||
* Default implementation of the {@link MethodInvoker} API. | ||
* | ||
* <p>This implementation never provides arguments to a {@link Method}. | ||
* | ||
* @author Sam Brannen | ||
* @since 6.1 | ||
*/ | ||
final class DefaultMethodInvoker implements MethodInvoker { | ||
|
||
private static final Log logger = LogFactory.getLog(DefaultMethodInvoker.class); | ||
|
||
|
||
@Override | ||
@Nullable | ||
public Object invoke(Method method, @Nullable Object target) throws Exception { | ||
Assert.notNull(method, "Method must not be null"); | ||
|
||
try { | ||
ReflectionUtils.makeAccessible(method); | ||
return method.invoke(target); | ||
} | ||
catch (InvocationTargetException ex) { | ||
if (logger.isErrorEnabled()) { | ||
logger.error("Exception encountered while invoking method [%s] on target [%s]" | ||
.formatted(method, target), ex.getTargetException()); | ||
} | ||
ReflectionUtils.rethrowException(ex.getTargetException()); | ||
// appease the compiler | ||
return null; | ||
} | ||
} | ||
|
||
} |
72 changes: 72 additions & 0 deletions
72
spring-test/src/main/java/org/springframework/test/context/MethodInvoker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Copyright 2002-2023 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 | ||
* | ||
* https://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.test.context; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
import org.springframework.lang.Nullable; | ||
|
||
/** | ||
* {@code MethodInvoker} defines a generic API for invoking a {@link Method} | ||
* within the <em>Spring TestContext Framework</em>. | ||
* | ||
* <p>Specifically, a {@code MethodInvoker} is made available to a | ||
* {@link TestExecutionListener} via {@link TestContext#getMethodInvoker()}, and | ||
* a {@code TestExecutionListener} can use the invoker to transparently benefit | ||
* from any special method invocation features of the underlying testing framework. | ||
* | ||
* <p>For example, when the underlying testing framework is JUnit Jupiter, a | ||
* {@code TestExecutionListener} can use a {@code MethodInvoker} to invoke | ||
* arbitrary methods with JUnit Jupiter's | ||
* {@linkplain org.junit.jupiter.api.extension.ExecutableInvoker parameter resolution | ||
* mechanism}. For other testing frameworks, the {@link #DEFAULT_INVOKER} will be | ||
* used. | ||
* | ||
* @author Sam Brannen | ||
* @since 6.1 | ||
* @see org.junit.jupiter.api.extension.ExecutableInvoker | ||
* @see org.springframework.util.MethodInvoker | ||
*/ | ||
public interface MethodInvoker { | ||
|
||
/** | ||
* Shared instance of the default {@link MethodInvoker}. | ||
* <p>This invoker never provides arguments to a {@link Method}. | ||
*/ | ||
static final MethodInvoker DEFAULT_INVOKER = new DefaultMethodInvoker(); | ||
|
||
|
||
/** | ||
* Invoke the supplied {@link Method} on the supplied {@code target}. | ||
* <p>When the {@link #DEFAULT_INVOKER} is used — for example, when | ||
* the underlying testing framework is JUnit 4 or TestNG — the method | ||
* must not declare any formal parameters. When the underlying testing | ||
* framework is JUnit Jupiter, parameters will be dynamically resolved via | ||
* registered {@link org.junit.jupiter.api.extension.ParameterResolver | ||
* ParameterResolvers} (such as the | ||
* {@link org.springframework.test.context.junit.jupiter.SpringExtension | ||
* SpringExtension}). | ||
* @param method the method to invoke | ||
* @param target the object on which to invoke the method, may be {@code null} | ||
* if the method is {@code static} | ||
* @return the value returned from the method invocation, potentially {@code null} | ||
* @throws Exception if any error occurs | ||
*/ | ||
@Nullable | ||
Object invoke(Method method, @Nullable Object target) throws Exception; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.