11

Is there some subtle reason why java.nio.ByteBuffer does not implement java.io.DataOutput or java.io.DataInput, or did the authors just not choose to do this? It would seem straightforward to map the calls (e.g. putInt() -> writeInt()).

The basic problem I (and some others, apparently) have is older classes which know how to serialize/serialize themselves using the generic interfaces: DataInput/DataOutput. I would like to reuse my custom serialization without writing a custom proxy for ByteBuffer.

Jonas
  • 121,568
  • 97
  • 310
  • 388
Justin
  • 4,437
  • 6
  • 32
  • 52

2 Answers2

5

Just wrap the buffer in ByteArrayInputStream or ByteArrayOutputStream using the put() or wrap() methods. The problem with having a ByteBuffer directly emulate a datainput/output stream has to do with not knowing the sizes in advance. What if there's an overrun?

What is needed is a ByteBufferOutputStream in which you can wrap / expose the required behaviors. Examples of this exist; the Apache avro serialization scheme has such a thing. It's not too hard to roll your own. Why is there not one by default? Well, it's not a perfect world...

ByteArrayOutputStream backing = new ByteArrayOutputStream();
DataOutput foo = new DataOutputStream(backing); 
// do your serialization out to foo

foo.close();
ByteBuffer buffer = ByteBuffer.wrap(backing.toByteArray());
// now you've got a bytebuffer...
Andrejs
  • 26,885
  • 12
  • 107
  • 96
andersoj
  • 22,406
  • 7
  • 62
  • 73
  • + for mentioning Avero, it looks interesting. – Justin Nov 01 '10 at 19:33
  • Overrun on read should throw EOFException; overrun on write would be treated just like writing to a full volume (or just throw EOF as well) – Justin Nov 01 '10 at 19:36
  • @Justin: Looking at the `DataOutput` api, yeah, that might work fine. Maybe it's worth a little experiment to make sure you can proxy `DataOutput` down onto a `ByteBuffer` cleanly and posting a bug at the oracle site or contacting the nio expert group. It may be that these two apis are intended to target different levels of abstraction; I'm not sure. – andersoj Nov 01 '10 at 19:40
  • @Justin: This also might be interesting to you. http://mina.apache.org/iobuffer.html – andersoj Nov 01 '10 at 19:42
  • For the `InputStream` case, see this related question: http://stackoverflow.com/questions/4332264/wrapping-a-bytebuffer-with-an-inputstream – Raedwald Jul 03 '13 at 10:47
  • 1
    Why are you calling close() on foo when it has no such method? https://docs.oracle.com/javase/8/docs/api/java/io/DataOutput.html – user2163960 Jul 02 '18 at 17:22
4

A better way that works with direct buffers too:

class ByteBufferOutputStream extends OutputStream
{
    private final ByteBuffer buffer;

    public ByteBufferOutputStream(ByteBuffer buffer)
    {
        this.buffer = buffer;
    }

    public void write(int b) throws IOException
    {
        buffer.put((byte) b);
    }
}

Note that this requires calling buffer.flip() after you are done writing to it, before you can read from it.

jbellis
  • 19,347
  • 2
  • 38
  • 47