FileChannel incompatibility introduced between 6 and 7 (and possible compiler bug)

David M. Lloyd david.lloyd at redhat.com
Thu Jul 26 11:44:11 PDT 2012


Ran into a pretty ugly little issue just now.  My NIO framework has a 
FileChannel subclass that it uses for certain tasks.  This works fine on 
7, but on 6 I get errors like this:

java.lang.NoClassDefFoundError: java/nio/channels/SeekableByteChannel

I found this odd, initially, because I never reference this interface. 
I noticed that in 7 this interface was introduced and (sensibly) 
retroactively added as a superinterface of FileChannel.  Logically this 
seems like it should not be a problem; it just means that in 7 we should 
have a couple new bridge methods on FileChannel (and we do):

   public java.nio.channels.SeekableByteChannel truncate(long) throws 
java.io.IOException;
     Code:
        0: aload_0
        1: lload_1
        2: invokevirtual #95 // Method 
truncate:(J)Ljava/nio/channels/FileChannel;
        5: areturn

   public java.nio.channels.SeekableByteChannel position(long) throws 
java.io.IOException;
     Code:
        0: aload_0
        1: lload_1
        2: invokevirtual #94 // Method 
position:(J)Ljava/nio/channels/FileChannel;
        5: areturn

Note the invokevirtual, which is specifically relevant here.

These methods are obviously necessary as FileChannel covariantly 
overrides the new interface methods.  However, the trouble started when 
I compiled my subclass and noticed, to my surprise, the very same bridge 
methods are on it!  Thus there's a static linkage from my class directly 
to SeekableByteChannel, despite there being no reference to it in the 
source code at all.

Now what bugs me about this is that if my class did not have these 
bridge methods, it would still work just fine, since the superclass is 
using invokevirtual to access the covariantly overridden method!  I 
could understand this behavior if it were using invokespecial, but it's 
not, or if I were actually directly implementing SeekableByteChannel on 
my class, which I'm not; the end result is what appears to be a needless 
break in compatibility.

Now I do have some options available - I can make mocks of the Java 7 
classes I need to compile against, and then compile against 6, or I can 
add a build-time step to strip these methods from the class.  But this 
strikes me as being a somewhat serious, if highly specific, problem.  Is 
this a compiler bug, or is it an irreparable backwards-compatibility 
mistake in NIO?

-- 
- DML



More information about the nio-dev mailing list