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