appendAllowed(true) breaks JSON array when the writer is opened/written/closed multiple times (original) (raw)

Bug description
When org.springframework.batch.infrastructure.item.json.JsonFileItemWriter is configured with setAppendAllowed(true) and used in multiple runs (open → write → close) against the same target file, the resulting file is not a valid JSON array. The second run appends data after the closing bracket (]) instead of inserting it inside the array with a comma.

Environment
Spring Batch 6.0.2

Steps to reproduce
Even with appendAllowed(true), after multiple runs the final file should remain a valid JSON array, and in the reproduction test below ["foo", "bar"] should be read correctly.

/*

package org.springframework.batch.infrastructure.item.json;

import java.io.File; import java.nio.file.Files;

import tools.jackson.databind.json.JsonMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension;

import org.springframework.batch.infrastructure.item.Chunk; import org.springframework.batch.infrastructure.item.ExecutionContext; import org.springframework.batch.infrastructure.item.json.JsonFileItemWriter; import org.springframework.batch.infrastructure.item.json.JsonObjectMarshaller; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.WritableResource;

import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows;

class JsonFileItemWriterTests {

private WritableResource resource;

@BeforeEach
void setUp() throws Exception {
    File file = Files.createTempFile("test", "json").toFile();
    this.resource = new FileSystemResource(file);
}

@Test
void appendAllowedShouldNotCorruptJsonArray() throws Exception {
    JsonFileItemWriter<String> writer = new JsonFileItemWriter<>(this.resource, new JacksonJsonObjectMarshaller<>());
    writer.setAppendAllowed(true);

    writer.open(new ExecutionContext());
    writer.write(Chunk.of("foo"));
    writer.close();

    writer.open(new ExecutionContext());
    writer.write(Chunk.of("bar"));
    writer.close();

    String[] result = readJsonArrayOfStrings();
    assertArrayEquals(new String[] { "foo", "bar" }, result);
}

private String[] readJsonArrayOfStrings() throws Exception {
    File file = this.resource.getFile();
    String raw = Files.readString(file.toPath());
    System.out.println(raw);
    return new JsonMapper().readValue(raw, String[].class);
}

}

current json structure

Expected behavior

expect json structure