@@ -20,7 +20,20 @@ internal class CharsetReader(
20
20
.onMalformedInput(CodingErrorAction .REPLACE )
21
21
.onUnmappableCharacter(CodingErrorAction .REPLACE )
22
22
byteBuffer = ByteBuffer .wrap(ByteArrayPool8k .take())
23
- byteBuffer.flip() // Make empty
23
+ // An explicit cast is needed here due to an API change in Java 9, see #2218.
24
+ //
25
+ // In Java 8 and earlier, the `flip` method was final in `Buffer`, and returned a `Buffer`.
26
+ // In Java 9 and later, the method was opened, and `ByteFuffer` overrides it, returning a `ByteBuffer`.
27
+ //
28
+ // You could observe this by decompiling this call with `javap`:
29
+ // Compiled with Java 8 it produces `INVOKEVIRTUAL java/nio/ByteBuffer.flip ()Ljava/nio/Buffer;`
30
+ // Compiled with Java 9+ it produces `INVOKEVIRTUAL java/nio/ByteBuffer.flip ()Ljava/nio/ByteBuffer;`
31
+ //
32
+ // This causes a `NoSuchMethodError` when running a class, compiled with a newer Java version, on Java 8.
33
+ //
34
+ // To mitigate that, `--bootclasspath` / `--release` options were introduced in `javac`, but there are no
35
+ // counterparts for these options in `kotlinc`, so an explicit cast is required.
36
+ (byteBuffer as Buffer ).flip() // Make empty
24
37
}
25
38
26
39
@Suppress(" NAME_SHADOWING" )
@@ -92,7 +105,7 @@ internal class CharsetReader(
92
105
if (bytesRead < 0 ) return bytesRead
93
106
byteBuffer.position(position + bytesRead)
94
107
} finally {
95
- byteBuffer.flip()
108
+ ( byteBuffer as Buffer ) .flip() // see the `init` block in this class for the reasoning behind the cast
96
109
}
97
110
return byteBuffer.remaining()
98
111
}
0 commit comments