In org.dbunit.AbstractDatabaseTester.executeOperation(DatabaseOperation, OperationType):
IDatabaseConnection connection = getConnection();
operationListener.connectionRetrieved(connection);
try
{
operation.execute(connection, getDataSet());
} finally
{
// Since 2.4.4 the OperationListener is responsible for closing
// the connection at the right time
if (type == OperationType.SET_UP)
{
operationListener.operationSetUpFinished(connection);
} else if (type == OperationType.TEAR_DOWN)
{
operationListener.operationTearDownFinished(connection);
} ...
}
connectionRetrieved(connection) is called before the try/finally block. If it throws, the exception propagates immediately — operation.execute() never runs, and critically, operationSetUpFinished()/operationTearDownFinished() in the finally block never run either. Per the method's own comment, the IOperationListener is supposed to be responsible for closing the connection at the right time, but that responsibility is never invoked on this path.
Impact: any IOperationListener implementation whose connectionRetrieved() can throw (a plausible pattern — a listener that validates or configures the connection on retrieval) loses its close guarantee on the failure path, leaving the connection unclosed on top of whatever error connectionRetrieved() reported. This is pre-existing behavior, not a regression.
Suggested direction: move connectionRetrieved(connection) inside the try block (or give it its own try/finally) so a thrown exception still reaches operationSetUpFinished()/operationTearDownFinished() for cleanup, matching the method's own stated contract.
Context: surfaced while reviewing the org.dbunit.annotation feature (issue #753, milestone 3.6.0) — its new PropertyApplyingOperationListener throws from connectionRetrieved() when a configured @DbUnitProperty value is malformed, which is what made this reachable in practice. The defect itself is in this pre-existing, foundational method and predates that branch, so filing separately rather than fixing it there.
In
org.dbunit.AbstractDatabaseTester.executeOperation(DatabaseOperation, OperationType):connectionRetrieved(connection)is called before thetry/finallyblock. If it throws, the exception propagates immediately —operation.execute()never runs, and critically,operationSetUpFinished()/operationTearDownFinished()in thefinallyblock never run either. Per the method's own comment, theIOperationListeneris supposed to be responsible for closing the connection at the right time, but that responsibility is never invoked on this path.Impact: any
IOperationListenerimplementation whoseconnectionRetrieved()can throw (a plausible pattern — a listener that validates or configures the connection on retrieval) loses its close guarantee on the failure path, leaving the connection unclosed on top of whatever errorconnectionRetrieved()reported. This is pre-existing behavior, not a regression.Suggested direction: move
connectionRetrieved(connection)inside thetryblock (or give it its own try/finally) so a thrown exception still reachesoperationSetUpFinished()/operationTearDownFinished()for cleanup, matching the method's own stated contract.Context: surfaced while reviewing the
org.dbunit.annotationfeature (issue #753, milestone 3.6.0) — its newPropertyApplyingOperationListenerthrows fromconnectionRetrieved()when a configured@DbUnitPropertyvalue is malformed, which is what made this reachable in practice. The defect itself is in this pre-existing, foundational method and predates that branch, so filing separately rather than fixing it there.