I just created a Gradle TestListener class that I was going to use to detect when a certain custom type of Exception is thrown from a test and use reflection to get the contents of a field in that exception class.
Here’s a simmered down version of what I’m doing:
public class MyExceptionListener implements TestListener {
private static final Logger log = LoggerFactory.getLogger(MyExceptionListener.class);
public void beforeSuite(TestDescriptor suite) {
}
public void afterSuite(TestDescriptor suite, TestResult result) {
}
public void beforeTest(TestDescriptor test) {
}
public void afterTest(TestDescriptor test, TestResult result) {
if (result.getFailedTestCount() > 0) {
Throwable t = result.getException();
// The following always prints out "org.gradle.internal.serialize.PlaceholderException"
System.out.println("exception: " + result.getException().getClass().getName());
// What I want to do is get to the actual exception instance and extract a field called "details"
// - need to do that through reflection since that class isn't available in the gradle classpath
if (t != null && t.getClass().getName().toLowerCase().contains("myexception")) {
try {
Object description = t.getClass().getField("description").get(t);
System.out.println("MyException description: " + description);
} catch (NoSuchFieldException nsfe) {
log.error("Unable to get description field from MyException through reflection.");
} catch (IllegalAccessException e) {
log.error("Unable to access description field from MyException through reflection.");
}
}
}
}
}
This is not working because all the exceptions I get are just PlaceholderException instances. That class has no methods to get the actual exception instance that occurred in the test run. I’ve tried calling getCause() but that just returns null. I also tried calling all other available methods on that class and while I can get the class name of the exception that actually occurred (by calling getExceptionClassName()) there is no way for me to get the original exception instance.
I read somewhere that this exception class is used when there is a problem serializing the original exception. I cannot find any reason for why that should be the case. The MyException class is quite simple, extends from RuntimeException which in turn extends Exception which implements Serializable. The only thing that the MyException class adds is the “details” string field so there shouldn’t be any problem serializing it.
Any ideas what’s going on here?