Skip to main content

Generics compiler bug?

Posted by fabriziogiudici on June 13, 2008 at 2:14 AM PDT

I've been using generics for a few years, and I'm happy with them. I'm
aware of the issues related to their design, and I agree that they
could have been made a bit better (but I understand the trade-offs made
for backward compability), but on the whole I consider them quite
useful for writing better code. I haven't had any problems so far, but
now I got stuck with a thing that looks like a compiler error. Consider
this class that I'm using as a transactional decorator (*) in my
NetBeans RCP stuff:



package it.tidalwave.bluemarine.persistence;



...



public abstract class TxTask

  {

    ...



    public abstract T run()

      throws E;

   

    public static T
execute (final TxTask task)

      {

       
return execute(RuntimeException.class, task);

      }

   

    public static Throwable> T execute (final Class
exceptionClass,

                                                     
final TxTask task)

      throws E

      {

           
try

             
{

               
...

               
try

                 
{

                   
result = task.run();

                   
...

                 
}

               
catch (RetryException e)

                 
{

                   
...

                 
}

               
catch (PersistenceException e)

                 
{

                   
...

                 
}

             
}

           
catch (Throwable t)

             
{

               
...



               
if (exceptionClass.isAssignableFrom(t.getClass()))

                 
{

////////////////////// THE PROBLEM IS HERE

                   
throw (E)t;

////////////////////// THE PROBLEM IS HERE

                 


               
throw (t instanceof RuntimeException) ? (RuntimeException)t : new
RuntimeException(t);

             
}



           
...

         
}

       

       
...

           


       
return result;

      }

  }



The peculiarity of this class is that it uses a generic in
the "throws" clause. This is ok with the language specifications, see
for instance the excellent href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Can%20I%20use%20a%20type%20parameter%20in%20in%20a%20throws%20clause">Angelika
Langer's tutorial on generics (even
though it's considered pretty useless in most cases, since you can't
throw a generified exception because of type erasure - but in my code
things are ok since I'm just rethrowing).



Now, the history of this issue is pretty complicated:

  1. The thing worked for several weeks, if not months (I remind
    you, in a NetBeans RCP project)
  2. At a certain point, I copied the class in the prototype of
    a
    web application, and I got a compiler error (see below); since I was
    focused on other things, I just commented out the offending part.
    blueMarine was still compiling ok.
  3. Since a few weeks, this is triggering the compiler error
    even in the NetBeans RCP project: but ONLY IF I BUILD THE WHOLE
    PROJECT (that is, if multiple *.java files are compiled at the same
    time). If I select the single TxTask.java file and compile it with
    the pop-up menu, it gets compiled ok (in fact, with this trick
    blueMarine builds, runs and passes the tests).

.../TxTask.java:169: unreported exception java.lang.Throwable; must be caught or declared to be thrown
throw (E)t;


This happens with the Java 5 compiler both on Mac OS X and Ubuntu
Linux. I've asked for help in a couple of mailing lists so far, without
success. So if you have any hints, please help: it is causing major
pain, since it's breaking the CI on Hudson. The full source of the
class is here: href="https://bluemarine.dev.java.net/svn/bluemarine/trunk/src/blueMarine-core/Core/Persistence/src/it/tidalwave/bluemarine/persistence/TxTask.java">
https://bluemarine.dev.java.net/svn/bluemarine/trunk/src/blueMarine-core/Core/Persistence/src/it/tidalwave/bluemarine/persistence/TxTask.java



(*) I'd like to get rid of this class sooner or later and use Spring or
EJB3 annotations for transactions - but this won't happen before the
next release, and I need to have CI working before that.

Comments

Thanks for the suggestion, it's one of the things I tried (together with other tricks such as encapsulating the thing in a method, etc...) but it doesn't make the error go away (it's an error, not a warning).

The benefit is important, the capability of wrapping any piece of code without changing the type of the exception it may throw.

As a sidenote, I suggest declaring the static methods as public static <T> T execute (final TxTask<T, ? extends RuntimeException> task) and public static <T, E extends Throwable> T execute (final Class<E> exceptionClass, final TxTask<T, ? extends E> task) throws E so that you'll be able to easily execute tasks declaring all kinds of RuntimeExceptions.

In my project I used to have problems compiling generics with Java 5 - from files compiling individually, but not together, to even compiler crashes; but they issues gradually went away while I was upgrading to latest version of Java 6. With 6.6 I don't see any of the issues I used to have. Maybe you should try compiling with Java 6. Also using "throw exceptionClass.cast(t)" instead of "throe (E)t" would make the warning go away. Last (and least) - perhaps I don't see a larger picture, but does parametrization on exception type actually give you any benefit? If not, I would suggest to simply avoid it... But again, I may be judging incorrectly based on a short snippet. HTH.

This bug is referenced here:
http://bugs.sun.com/view_bug.do?bug_id=6280975

It was fixed when working on JSR 199
http://bugs.sun.com/view_bug.do?bug_id=6199662

Rémi

Ok, I'll never be able to escape all the stuff and post the code here... look at the comment at DZone: http://netbeans.dzone.com/news/generics-compiler-bug#comment-4085

Ok, my Hudson thanks for the advice :-) In my NetBeans RCP project I worked around the problem by adding this in the build.xml file Basically, it overrides the target for compiling the project and makes sure that the TxTask file is compiled alone before the others.

Ops, yes, thanks for the clarification. I can't use Java 6 on my MBP >:-( but I'll try to set up javac -target 1.5 on my CI server, which is a Linux box.

It's not strange, it's a bug in the compiler architecture so it can't be easily backported. So the bug is corrected in jdk 6 but is not corrected in jdk5.
Also note that jdk6 compiler can generate 1.5 compatible classes using -target 1.5

Rémi

Thanks Rèmi. Both issues are closed since a few years - so it seems I'm triggering it again... Very strange, I'll try to post a test case to the bug parade.