So I decided to build my own...
So lets see what this class does. First we need 3x of CallableStatements to hold the statements for enabling, disabling and capturing DBMS_OUTPUT. Then there's a variable to keep track of how many lines we fetch from the database at one time, and a default value for this variable.
The two constructors are used to prepare all of the callable statements via the passed in Connection, with one of the constructors allowing us to overwrite the default number of lines fetched.
The brains of this code is in the execute() method. This method accepts a CallableStatement that we wish to capture DBMS_OUTPUT for. To capture output we first run the statement to enable it, then execute the passed in statement, loop over the DBMS_OUTPUT lines, run the disable statement and return the results as a List<String>.
The documentation for GET_LINES states... "After retrieving the specified number of lines, the procedure returns the number of lines actually retrieved. If this number is less than the number of lines requested, then there are no more lines in the buffer." So this is where the do..while loop comes in. We simply try to fetch the maximum number of lines (as configured in the constructors) until we fetch less than that number. The inner for loop is used to copy returned lines in the current batch to the list of all lines with nulls changed to empty strings.
The close() method simply closes all of the internally used CallableStatement objects and returns.
This is how you use this class...
It's nice and simple, just instantiate it with a Connection and then run execute(). This mimics what the Connection class would do anyway so it's a simple drop-in replacement. Since this class implements AutoCloseable, you can use it in a try-with-resources statement too.