lifetime of UNO objects, writing Java exception-safe code

Lionel Elie Mamane lionel at mamane.lu
Sun Sep 15 07:23:10 PDT 2013


On Fri, Sep 13, 2013 at 02:28:35PM +0200, Stephan Bergmann wrote:
> On 09/13/2013 11:07 AM, Lionel Elie Mamane wrote:
>> On Wed, Sep 11, 2013 at 12:35:15PM +0200, Stephan Bergmann wrote:

>>> First, note that we don't have reference-counting garbage collection
>>> in general in UNO.  For example, Java-UNO doesn't use
>>> reference-counting.

>>> Second, note that there needs to be code (the "owner" in the jargon
>>> of the udkapi/com/sun/star/lang/XComponent.idl documentation) that
>>> explicitly calls dispose on a UNO object.  It is not magically
>>> called when a UNO object becomes unreachable.

>> So let's take the concrete example of
>>   reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java
>>   around line 233:
>>   private String getOrderStatement(final int commandType, final String command, final List sortExpressions)

>> Concretely, the Java code does:

>>    final XComponent[] hold = new XComponent[1];
>>    final XNameAccess columns = getFieldsByCommandDescriptor(commandType, command, hold);

>> I assume this whole rigmarole with "hold" is to ensure that
>> "dispose()" is called on "columns", providing an owner for it.
>> (I assume it uses this round-about way instead of just declaring the
>>   caller the owner of columns because in some conditions columns will be
>>   a temporary and in other conditions, it will not; with this setup,
>>   this is testable with (hold[0] == null)).

> (At least the documentation you cite above does not make it look
> like keepFieldsAlive could return a null reference.)

In my quote of the documentation, I simplified this point away. It
depends. Sometimes it returns a temporary object (owned by
another temporary that is put in keepFieldsAlive) and sometimes it
returns a long-lived "shared" object that the caller should *not*
dispose.

>> So I need to do something like:

>>   final XComponent[] hold = new XComponent[1];
>>   try
>>   {
>>     (...)
>>     final XNameAccess columns = getFieldsByCommandDescriptor(commandType, command, hold);
>>     (...)
>>     if(hold[0] != null)
>>        hold[0].dispose();
>>   }
>>   catch (SQLException ex)
>>   {
>>      if(hold[0] != null)
>>        hold[0].dispose();
>>      LOGGER.error("ReportProcessing failed", ex);
>>   }
>>   catch(java.lang.Exception e)
>>   {
>>     if(hold[0] != null)
>>       hold.dispose();
>>     throw e;
>>   }

> Why not use a finally block?

Because my knowledge of Java is limited to what I had to
learn. finally blocks seem to be *exactly* what is needed
indeed. Thanks for the pointer.

>> Did I understand what you were saying correctly? This function (and
>> _any_ code getting a fresh/temporary UNO object) needs to clean up
>> after itself manually in this pedestrian, error-prone way? Do we get a
>> cop-out in C++ because of the use of com::sun::star::uno::Reference
>> which calls _pInterface->release()? Do we get a cop-out in any other
>> UNO language? (Python? Basic?)

> This specific Java code obtaining ownership of an XComponent is
> supposed to follow the protocol of XComponent and ensure that
> dispose is called, yes.  But not every UNO object implements the
> XComponent protocol, so there is lots of code obtaining references
> to UNO objects that does not need to do this sort of clean-up.

So basically, the documentation of the API call should tell you
whether you have to do that or not. OK.

-- 
Lionel


More information about the LibreOffice mailing list