So in my spare time I decided to write a utility class that would let me capture DBMS_OUTPUT lines in case I wanted to do something like this in the future. This isn't exactly new and has been covered here and on Ask Tom, however I didn't like either of those approaches. I wanted my utility class to work with try-with-resources so that I wouldn't have to write any boring boiler plate code when using this utility.
This is what I came up with...
This utility class requires a Connection object to be passed into its constructor. There is an overloaded constructor that also takes an int, specifying the number of lines to read back from the database in one go; this can be useful for performance tuning. The execute() method is used to execute your CallableStatement and returns a list of Strings, one String per line of DBMS_OUTPUT captured.
Output is read back from the database using the GET_LINES Procedure until no more output is available. DBMS_OUTPUT is enabled before userCall is executed, and then disabled after its execution is completed and all output is captured.
Using this utility is simple, create a Connection and your CallableStatement that you want to run and capture DBMS_OUTPUT from. Then create the DbmsOutputCapture class passing in the conn object. Call execute() on the capture object. Because DbmsOutputCapture implements AutoCloseable there is no need to mess around with closing it manually.
The capture object is reusable multiple times, so if you have several CallableStatements to execute and capture DBMS_OUTPUT from, you only need to instantiate one copy of DbmsOutputCapture.