Skip to content

Commit 5e05a84

Browse files
committed
Refined check for NoClassDefFoundError in getTestExecutionListeners()
Issue: SPR-11804 (cherry picked from commit a2ef2c9)
1 parent c7b2ac7 commit 5e05a84

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

spring-test/src/main/java/org/springframework/test/context/TestContextManager.java

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.commons.logging.Log;
2828
import org.apache.commons.logging.LogFactory;
2929

30+
import org.springframework.beans.BeanInstantiationException;
3031
import org.springframework.beans.BeanUtils;
3132
import org.springframework.core.annotation.AnnotationUtils;
3233
import org.springframework.util.Assert;
@@ -49,18 +50,18 @@
4950
* <ul>
5051
* <li>{@link #beforeTestClass() before test class execution}: prior to any
5152
* <em>before class methods</em> of a particular testing framework (e.g., JUnit
52-
* 4's {@link org.junit.BeforeClass &#064;BeforeClass})</li>
53+
* 4's {@link org.junit.BeforeClass @BeforeClass})</li>
5354
* <li>{@link #prepareTestInstance(Object) test instance preparation}:
5455
* immediately following instantiation of the test instance</li>
5556
* <li>{@link #beforeTestMethod(Object, Method) before test method execution}:
5657
* prior to any <em>before methods</em> of a particular testing framework (e.g.,
57-
* JUnit 4's {@link org.junit.Before &#064;Before})</li>
58+
* JUnit 4's {@link org.junit.Before @Before})</li>
5859
* <li>{@link #afterTestMethod(Object, Method, Throwable) after test method
5960
* execution}: after any <em>after methods</em> of a particular testing
60-
* framework (e.g., JUnit 4's {@link org.junit.After &#064;After})</li>
61+
* framework (e.g., JUnit 4's {@link org.junit.After @After})</li>
6162
* <li>{@link #afterTestClass() after test class execution}: after any
6263
* <em>after class methods</em> of a particular testing framework (e.g., JUnit
63-
* 4's {@link org.junit.AfterClass &#064;AfterClass})</li>
64+
* 4's {@link org.junit.AfterClass @AfterClass})</li>
6465
* </ul>
6566
*
6667
* @author Sam Brannen
@@ -74,10 +75,10 @@
7475
public class TestContextManager {
7576

7677
private static final String[] DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = new String[] {
77-
"org.springframework.test.context.web.ServletTestExecutionListener",
78-
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
79-
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
80-
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
78+
"org.springframework.test.context.web.ServletTestExecutionListener",
79+
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
80+
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
81+
"org.springframework.test.context.transaction.TransactionalTestExecutionListener" };
8182

8283
private static final Log logger = LogFactory.getLog(TestContextManager.class);
8384

@@ -164,10 +165,10 @@ private List<TestExecutionListener> getReversedTestExecutionListeners() {
164165

165166
/**
166167
* Retrieve an array of newly instantiated {@link TestExecutionListener TestExecutionListeners}
167-
* for the specified {@link Class class}. If {@link TestExecutionListeners &#064;TestExecutionListeners}
168+
* for the specified {@link Class class}. If {@link TestExecutionListeners @TestExecutionListeners}
168169
* is not <em>present</em> on the supplied class, the default listeners will be returned.
169170
* <p>Note that the {@link TestExecutionListeners#inheritListeners() inheritListeners} flag of
170-
* {@link TestExecutionListeners &#064;TestExecutionListeners} will be taken into consideration.
171+
* {@link TestExecutionListeners @TestExecutionListeners} will be taken into consideration.
171172
* Specifically, if the {@code inheritListeners} flag is set to {@code true}, listeners
172173
* defined in the annotated class will be appended to the listeners defined in superclasses.
173174
* @param clazz the test class for which the listeners should be retrieved
@@ -198,12 +199,10 @@ private TestExecutionListener[] retrieveTestExecutionListeners(Class<?> clazz) {
198199
Class<? extends TestExecutionListener>[] valueListenerClasses = testExecutionListeners.value();
199200
Class<? extends TestExecutionListener>[] listenerClasses = testExecutionListeners.listeners();
200201
if (!ObjectUtils.isEmpty(valueListenerClasses) && !ObjectUtils.isEmpty(listenerClasses)) {
201-
String msg = String.format("Test class [%s] has been configured with @TestExecutionListeners' " +
202-
"'value' [%s] and 'listeners' [%s] attributes. Use one or the other, but not both.",
202+
throw new IllegalStateException(String.format("Class [%s] configured with @TestExecutionListeners' " +
203+
"'value' [%s] and 'listeners' [%s] attributes. Use one or the other, but not both.",
203204
declaringClass, ObjectUtils.nullSafeToString(valueListenerClasses),
204-
ObjectUtils.nullSafeToString(listenerClasses));
205-
logger.error(msg);
206-
throw new IllegalStateException(msg);
205+
ObjectUtils.nullSafeToString(listenerClasses)));
207206
}
208207
else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
209208
listenerClasses = valueListenerClasses;
@@ -213,20 +212,30 @@ else if (!ObjectUtils.isEmpty(valueListenerClasses)) {
213212
classesList.addAll(0, Arrays.<Class<? extends TestExecutionListener>> asList(listenerClasses));
214213
}
215214
declaringClass = (testExecutionListeners.inheritListeners() ? AnnotationUtils.findAnnotationDeclaringClass(
216-
annotationType, declaringClass.getSuperclass()) : null);
215+
annotationType, declaringClass.getSuperclass()) : null);
217216
}
218217
}
219218

220219
List<TestExecutionListener> listeners = new ArrayList<TestExecutionListener>(classesList.size());
221220
for (Class<? extends TestExecutionListener> listenerClass : classesList) {
221+
NoClassDefFoundError ncdfe = null;
222222
try {
223223
listeners.add(BeanUtils.instantiateClass(listenerClass));
224224
}
225225
catch (NoClassDefFoundError err) {
226+
ncdfe = err;
227+
}
228+
catch (BeanInstantiationException ex) {
229+
if (ex.getCause() instanceof NoClassDefFoundError) {
230+
ncdfe = (NoClassDefFoundError) ex.getCause();
231+
}
232+
}
233+
if (ncdfe != null) {
226234
if (logger.isInfoEnabled()) {
227-
logger.info(String.format("Could not instantiate TestExecutionListener class [%s]. " +
235+
logger.info(String.format("Could not instantiate TestExecutionListener [%s]. " +
228236
"Specify custom listener classes or make the default listener classes " +
229-
"(and their dependencies) available.", listenerClass.getName()));
237+
"(and their required dependencies) available. Offending class: [%s]",
238+
listenerClass.getName(), ncdfe.getMessage()));
230239
}
231240
}
232241
}
@@ -258,7 +267,7 @@ protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionLis
258267
* Hook for pre-processing a test class <em>before</em> execution of any
259268
* tests within the class. Should be called prior to any framework-specific
260269
* <em>before class methods</em> (e.g., methods annotated with JUnit's
261-
* {@link org.junit.BeforeClass &#064;BeforeClass}).
270+
* {@link org.junit.BeforeClass @BeforeClass}).
262271
* <p>An attempt will be made to give each registered
263272
* {@link TestExecutionListener} a chance to pre-process the test class
264273
* execution. If a listener throws an exception, however, the remaining
@@ -324,7 +333,7 @@ public void prepareTestInstance(Object testInstance) throws Exception {
324333
* {@link Method test method}, for example for setting up test fixtures,
325334
* starting a transaction, etc. Should be called prior to any
326335
* framework-specific <em>before methods</em> (e.g., methods annotated with
327-
* JUnit's {@link org.junit.Before &#064;Before}).
336+
* JUnit's {@link org.junit.Before @Before}).
328337
* <p>The managed {@link TestContext} will be updated with the supplied
329338
* {@code testInstance} and {@code testMethod}.
330339
* <p>An attempt will be made to give each registered
@@ -362,7 +371,7 @@ public void beforeTestMethod(Object testInstance, Method testMethod) throws Exce
362371
* {@link Method test method}, for example for tearing down test fixtures,
363372
* ending a transaction, etc. Should be called after any framework-specific
364373
* <em>after methods</em> (e.g., methods annotated with JUnit's
365-
* {@link org.junit.After &#064;After}).
374+
* {@link org.junit.After @After}).
366375
* <p>The managed {@link TestContext} will be updated with the supplied
367376
* {@code testInstance}, {@code testMethod}, and
368377
* {@code exception}.
@@ -414,7 +423,7 @@ public void afterTestMethod(Object testInstance, Method testMethod, Throwable ex
414423
* Hook for post-processing a test class <em>after</em> execution of all
415424
* tests within the class. Should be called after any framework-specific
416425
* <em>after class methods</em> (e.g., methods annotated with JUnit's
417-
* {@link org.junit.AfterClass &#064;AfterClass}).
426+
* {@link org.junit.AfterClass @AfterClass}).
418427
* <p>Each registered {@link TestExecutionListener} will be given a chance to
419428
* post-process the test class. If a listener throws an exception, the
420429
* remaining registered listeners will still be called, but the first

0 commit comments

Comments
 (0)