Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid making defensive copies of ByteBuffer?

I've got a class that takes a ByteBuffer as a constructor argument. Is there a way to avoid making defensive copies in order to ensure that the buffer doesn't get modified past that point?

ByteBuffer.isReadOnly() doesn't guarantee that the original owner won't modifying the buffer. To make matters worse, there doesn't seem to be a way to subclass ByteBuffer. Any ideas?

like image 779
Gili Avatar asked Oct 03 '11 15:10

Gili


People also ask

What is defensive copy in Java?

Defensive copying. A mutable object is simply an object which can change its state after construction. For example, StringBuilder and Date are mutable objects, while String and Integer are immutable objects. A class may have a mutable object as a field.

What does ByteBuffer wrap do?

wrap. Wraps a byte array into a buffer. The new buffer will be backed by the given byte array; that is, modifications to the buffer will cause the array to be modified and vice versa. The new buffer's capacity and limit will be array.

What is a direct ByteBuffer?

A direct buffer is a chunk of native memory shared with Java from which you can perform a direct read. An instance of DirectByteBuffer can be created using the ByteBuffer.

How do I copy byte buffer?

ByteBuffer duplicate() method in Java A duplicate buffer of a buffer can be created using the method duplicate() in the class java. nio. ByteBuffer. This duplicate buffer is identical to the original buffer.


2 Answers

The only real way is, as you say, buf.asReadOnlyBuffer(), then pass this into the constructor. There's no other option apart from this, although you could do a copy of the contents into a new ByteBuffer, then pass that.

like image 176
Chris Dennett Avatar answered Sep 23 '22 02:09

Chris Dennett


This is the best I could do for now:

/**
 * Helper functions for java.nio.Buffer.
 * <p/>
 * @author Gili Tzabari
 */
public final class Buffers
{
    /**
     * Returns a ByteBuffer that is identical but distinct from the original buffer.
     * <p/>
     * @param original the buffer to copy
     * @return an independent copy of original
     * @throws NullPointerException if original is null
     */
    public static ByteBuffer clone(ByteBuffer original)
    {
        Preconditions.checkNotNull(original, "original may not be null");

        ByteBuffer result = ByteBuffer.allocate(original.capacity());
        ByteBuffer source = original.duplicate();
        source.rewind();
        result.put(source);

        try
        {
            source.reset();
            result.position(source.position());
            result.mark();
        }
        catch (InvalidMarkException unused)
        {
            // Mark is unset, ignore.
        }
        result.position(original.position());
        result.limit(original.limit());
        return result;
    }

    /**
     * Returns an array representation of a buffer. The returned buffer may, or may not, be tied to
     * the underlying buffer's contents (so it should not be modified).
     * <p/>
     * @param buffer the buffer
     * @return the remaining bytes
     */
    public static byte[] toArray(ByteBuffer buffer)
    {
        if (buffer.hasArray() && !buffer.isReadOnly() && buffer.position() == 0
            && buffer.remaining() == buffer.limit())
        {
            return buffer.array();
        }
        ByteBuffer copy = buffer.duplicate();
        byte[] result = new byte[copy.remaining()];
        copy.get(result);
        return result;
    }

    /**
     * Prevent construction.
     */
    private Buffers()
    {
    }
}

I've also filed a feature request with Oracle: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7130631

like image 39
Gili Avatar answered Sep 22 '22 02:09

Gili