Skip to content

Commit 115a6c4

Browse files
Correctly handle exceptions from providers (close #760)
1 parent f45489f commit 115a6c4

7 files changed

Lines changed: 35 additions & 35 deletions

File tree

core/src/main/java/org/easymock/internal/ClassProxyFactory.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,21 +145,22 @@ public static boolean isCallerMockInvocationHandlerInvoke(Throwable e) {
145145

146146
@Override
147147
public <T> T createProxy(final Class<T> toMock, InvocationHandler handler, Method[] mockedMethods, ConstructorArgs args) {
148-
Throwable kept = null;
148+
RuntimeException exception = null;
149149
// We pick the provider we think will work
150150
// But we still loop around all the providers just in case we are wrong when picking but that one will eventually work
151151
ClassInfoProvider[] providers = isJdkClassOrWithoutPackage(toMock) ? jdkClassInfoProviders : defaultClassInfoProviders;
152152
for (ClassInfoProvider provider : providers) {
153153
try {
154154
return doCreateProxy(toMock, handler, provider, mockedMethods, args);
155-
} catch (Error | RuntimeException e) {
156-
kept = e;
155+
} catch (Throwable e) {
156+
if (exception == null) {
157+
exception = new RuntimeException("Failed to mock " + toMock + " with provider " + provider, e);
158+
} else {
159+
exception.addSuppressed(e);
160+
}
157161
}
158162
}
159-
if (kept instanceof Error) {
160-
throw (Error) kept;
161-
}
162-
throw (RuntimeException) kept;
163+
throw exception;
163164
}
164165

165166
@IgnoreAnimalSniffer // It reports errors on MethodHandle.invoke

core/src/main/java/org/easymock/internal/MocksControl.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ public <T, R> R createMock(String name, Class<T> toMock, ConstructorArgs constru
110110
R mock = (R) proxyFactory.createProxy(toMock, new ObjectMethodsFilter(toMock,
111111
new MockInvocationHandler(this), name), mockedMethods, constructorArgs);
112112
return mock;
113-
} catch (NoClassDefFoundError e) {
114-
if(e.getMessage().startsWith("org/objenesis")) {
113+
} catch (RuntimeException e) {
114+
// special case where Objenesis is not in the classpath and we try to mock classes
115+
if(e.getCause() instanceof NoClassDefFoundError && e.getCause().getMessage().startsWith("org/objenesis")) {
115116
throw new RuntimeExceptionWrapper(new RuntimeException(
116-
"Class mocking requires to have Objenesis library in the classpath", e));
117+
"Class mocking requires to have Objenesis library in the classpath", e.getCause()));
117118
}
118119
throw e;
119120
}

core/src/main/java/org/easymock/internal/classinfoprovider/DefaultClassInfoProvider.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ public <T> ClassLoader classLoader(Class<T> toMock) {
3030
return toMock.getClassLoader();
3131
}
3232

33+
@Override
34+
public String toString() {
35+
return getClass().getSimpleName();
36+
}
3337
}

core/src/main/java/org/easymock/internal/classinfoprovider/JdkClassInfoProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,10 @@ public String classPackage(Class<?> toMock) {
2929
public <T> ClassLoader classLoader(Class<T> toMock) {
3030
return getClass().getClassLoader();
3131
}
32+
33+
@Override
34+
public String toString() {
35+
return getClass().getSimpleName();
36+
}
37+
3238
}

core/src/test/java/org/easymock/tests/DefaultClassInstantiatorTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,14 @@ public void objectParamRecursion() {
165165
@Test
166166
public void constructorWithCodeLimitation() {
167167
Exception e = assertThrows(Exception.class, () -> createMock(ConstructorWithCodeClass.class));
168-
assertEquals("Failed to instantiate org.easymock.tests.DefaultClassInstantiatorTest$ConstructorWithCodeClass's mock: ", e.getMessage());
168+
assertEquals("Failed to mock class org.easymock.tests.DefaultClassInstantiatorTest$ConstructorWithCodeClass with provider DefaultClassInfoProvider", e.getMessage());
169169
}
170170

171171
@Test
172172
public void privateConstructorLimitation() {
173173
Exception e = assertThrows(Exception.class, () -> createMock(PrivateConstructorClass.class));
174-
assertEquals("No visible constructors in class org.easymock.tests.DefaultClassInstantiatorTest$PrivateConstructorClass", e.getMessage());
174+
assertEquals("Failed to mock class org.easymock.tests.DefaultClassInstantiatorTest$PrivateConstructorClass with provider DefaultClassInfoProvider", e.getMessage());
175+
assertEquals("No visible constructors in class org.easymock.tests.DefaultClassInstantiatorTest$PrivateConstructorClass", e.getCause().getMessage());
175176
}
176177

177178
@Test

core/src/test/java/org/easymock/tests2/PartialMockingTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ public void testPartialMock_InvalidParams() {
109109
public void testPartialMock_ExceptionInConstructor() {
110110
RuntimeException ex = assertThrows(RuntimeException.class,
111111
() -> createMockBuilder(ArrayList.class).withConstructor(-5).createMock());
112-
Assertions.assertEquals("Failed to instantiate mock calling constructor: Exception in constructor", ex.getMessage());
112+
Assertions.assertEquals("Failed to mock class java.util.ArrayList with provider JdkClassInfoProvider", ex.getMessage());
113+
Assertions.assertEquals("Failed to instantiate mock calling constructor: Exception in constructor", ex.getCause().getMessage());
113114
}
114115

115116
@Test

test-nodeps/src/test/java/org/itests/DependencyTest.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,9 @@ public void testInterfaceMocking() {
4848

4949
@Test
5050
public void testClassMocking() {
51-
try {
52-
createMock(DependencyTest.class);
53-
fail("Should throw an exception due to a NoClassDefFoundError");
54-
} catch (RuntimeException e) {
55-
assertEquals("Class mocking requires to have Objenesis library in the classpath", e
56-
.getMessage());
57-
assertTrue(e.getCause() instanceof NoClassDefFoundError);
58-
}
51+
RuntimeException e = assertThrows(RuntimeException.class, () -> createMock(DependencyTest.class));
52+
assertEquals("Class mocking requires to have Objenesis library in the classpath", e.getMessage());
53+
assertTrue(e.getCause() instanceof NoClassDefFoundError);
5954
}
6055

6156
@Test
@@ -69,23 +64,14 @@ public void testInterfaceMockingSupport() {
6964

7065
@Test
7166
public void testClassMockingSupport() {
72-
try {
73-
support.createMock(DependencyTest.class);
74-
fail("Should throw an exception due to a NoClassDefFoundError");
75-
} catch (RuntimeException e) {
76-
assertEquals("Class mocking requires to have Objenesis library in the classpath", e
77-
.getMessage());
78-
assertTrue(e.getCause() instanceof NoClassDefFoundError);
79-
}
67+
RuntimeException e = assertThrows(RuntimeException.class, () -> support.createMock(DependencyTest.class));
68+
assertEquals("Class mocking requires to have Objenesis library in the classpath", e.getMessage());
69+
assertTrue(e.getCause() instanceof NoClassDefFoundError);
8070
}
8171

8272
@Test
8373
public void testStillNoClassDefFoundErrorWhenSomeOtherClassIsMissing() {
84-
try {
85-
support.createMock(Main.class);
86-
fail("Should throw an exception due to a NoClassDefFoundError");
87-
} catch (NoClassDefFoundError e) {
88-
assertEquals("org/depends/Dependency", e.getMessage());
89-
}
74+
NoClassDefFoundError e = assertThrows(NoClassDefFoundError.class, () -> support.createMock(Main.class));
75+
assertEquals("org/depends/Dependency", e.getMessage());
9076
}
9177
}

0 commit comments

Comments
 (0)