Affects: 6.*.*


The following test fails:

import static org.junit.jupiter.api.Assertions.*;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Test;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;

class DefaultDataBufferStringTransformationTest {

    @Test
    void test() {
        Charset charset = StandardCharsets.UTF_8;
        DataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.allocateBuffer(DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY);
        String name = "Müller";
        int repeatCount = 19;
        for(int i = 0; i < repeatCount; i++) {
            dataBuffer.write(name, charset);
        }
        String expected = name.repeat(repeatCount);
        String result = dataBuffer.toString(charset);
        assertEquals(expected, result);
    }

}

May be it has something to do with this issue.

Comment From: sdeleuze

I can indeed reproduce:

Expected :MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
Actual   :MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerler

@poutsma Maybe you want to tackle this one since it could be indeed potentially related to #30966.

Comment From: sbrannen

Out of curiosity, I took a glance at this yesterday, and I think the issue might be in DataBuffer#write(CharSequence, Charset) instead of in DefaultDataBuffer.

If you add System.out.println(toString(StandardCharsets.UTF_8)); to the write() method immediately after writePosition(dest.position());, you'll see the following.

Müller
MüllerMüller
MüllerMüllerMüller
MüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMül
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüller
MüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerMüllerler

The error occurs when the current ByteBuffer does not contain enough remaining space to hold the content of the supplied CharSequence and the DataBuffer's capacity has to be increased.

In the last three lines of the above output you can see that first Mül is written, then Mül is gone, and then ler is written. So the initial Mül is effectively lost.

This occurs when adding the encoded CharSet content of length L to the current buffer with size B exceeds the initial capacity C divided by 2.

So, when B + L > C/2.

C = DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY = 256.

C / 2 = 128

For the 18th iteration: B + L = 7 * 18 = 126 (7 because ü takes up two positions when encoded), and 127 < 128. So no error occurs.

For the 19th iteration: B + L = 7 * 19 = 133, and 133 > 128, and content is lost as described above.