-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Milestone
Description
This happens with all Jackson versions. The below test sadly passes:
@Test
public void byteBufferInJacksonIsBroken() throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocate(2);
byteBuffer.put((byte) 1);
byteBuffer.put((byte) 2);
byteBuffer.position(1);
ByteBuffer slice = byteBuffer.slice();
assertThat(slice.position()).isZero();
assertThat(slice.capacity()).isEqualTo(1);
ByteBuffer serde = serde(slice);
assertThat(serde.position()).isZero();
assertThat(serde.capacity()).isEqualTo(2);
assertThat(serde.get()).isEqualTo((byte) 1);
assertThat(slice.get()).isEqualTo((byte) 2);
}
private ByteBuffer serde(ByteBuffer t) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(mapper.writeValueAsBytes(t), ByteBuffer.class);
}
There are two bugs, really:
- Java ByteBuffer equality is defined by the bytes remaining being equivalent, but Jackson rewinds the buffer so Jackson will happily serialise bytes which are not in the view. This is not visible above, but if instead of calling byteBuffer.slice() you call byteBuffer.duplicate() you will have the same issue (but slice.position() is not zero and the lengths are the same).
- Secondly, if the ByteBuffer has wrapped an array, Jackson assumes that the ByteBuffer starts at the start of the array, which is not true.
What kind of fix would be accepted here?
My ideal scenario is that ByteBufferSerializer is rewritten to
public class ByteBufferSerializer extends StdScalarSerializer<ByteBuffer>
{
public ByteBufferSerializer() { super(ByteBuffer.class); }
@Override
public void serialize(ByteBuffer bbuf, JsonGenerator gen, SerializerProvider provider) throws IOException
{
if (bbuf.hasArray()) {
gen.writeBinary(bbuf.array(), bbuf.arrayOffset() + bbuf.position(), bbuf.arrayOffset() + bbuf.limit());
return;
}
ByteBuffer copy = bbuf.asReadOnlyBuffer();
InputStream in = new ByteBufferBackedInputStream(copy);
gen.writeBinary(in, copy.remaining());
in.close();
}
}
but I could also see it being rewritten to
public class ByteBufferSerializer extends StdScalarSerializer<ByteBuffer>
{
public ByteBufferSerializer() { super(ByteBuffer.class); }
@Override
public void serialize(ByteBuffer bbuf, JsonGenerator gen, SerializerProvider provider) throws IOException
{
if (bbuf.hasArray()) {
gen.writeBinary(bbuf.array(), bbuf.arrayOffset(), bbuf.arrayOffset() + bbuf.limit());
return;
}
ByteBuffer copy = bbuf.asReadOnlyBuffer();
if (copy.position() > 0) {
copy.rewind();
}
InputStream in = new ByteBufferBackedInputStream(copy);
gen.writeBinary(in, copy.remaining());
in.close();
}
}
- I accept that my former solution changes behaviour a little more drastically (but makes it consistent with equals()
).
Metadata
Metadata
Assignees
Labels
No labels