1616
1717package org .springframework .batch .infrastructure .item .json ;
1818
19+ import java .io .File ;
20+ import java .io .IOException ;
21+ import java .io .RandomAccessFile ;
1922import java .util .Iterator ;
2023
2124import org .springframework .batch .infrastructure .item .Chunk ;
25+ import org .springframework .batch .infrastructure .item .ExecutionContext ;
26+ import org .springframework .batch .infrastructure .item .ItemStreamException ;
2227import org .springframework .batch .infrastructure .item .support .AbstractFileItemWriter ;
2328import org .springframework .core .io .WritableResource ;
2429import org .springframework .util .Assert ;
4651 * @param <T> type of object to write as json representation
4752 * @author Mahmoud Ben Hassine
4853 * @author Jimmy Praet
54+ * @author Yanming Zhou
4955 * @since 4.1
5056 */
5157public class JsonFileItemWriter <T > extends AbstractFileItemWriter <T > {
@@ -58,6 +64,8 @@ public class JsonFileItemWriter<T> extends AbstractFileItemWriter<T> {
5864
5965 private JsonObjectMarshaller <T > jsonObjectMarshaller ;
6066
67+ private boolean hasExistingItems ;
68+
6169 /**
6270 * Create a new {@link JsonFileItemWriter} instance.
6371 * @param resource to write json data to
@@ -91,10 +99,27 @@ public void setJsonObjectMarshaller(JsonObjectMarshaller<T> jsonObjectMarshaller
9199 this .jsonObjectMarshaller = jsonObjectMarshaller ;
92100 }
93101
102+ @ Override
103+ public void open (ExecutionContext executionContext ) throws ItemStreamException {
104+ super .open (executionContext );
105+ if (this .append && this .resource != null && this .resource .exists ()) {
106+ try {
107+ this .hasExistingItems = reopen (this .resource .getFile ());
108+ }
109+ catch (IOException ex ) {
110+ throw new ItemStreamException (ex .getMessage (), ex );
111+ }
112+ }
113+ }
114+
94115 @ SuppressWarnings ("DataFlowIssue" )
95116 @ Override
96117 public String doWrite (Chunk <? extends T > items ) {
97118 StringBuilder lines = new StringBuilder ();
119+ if (this .hasExistingItems ) {
120+ lines .append (JSON_OBJECT_SEPARATOR ).append (this .lineSeparator );
121+ this .hasExistingItems = false ;
122+ }
98123 Iterator <? extends T > iterator = items .iterator ();
99124 if (!items .isEmpty () && state .getLinesWritten () > 0 ) {
100125 lines .append (JSON_OBJECT_SEPARATOR ).append (this .lineSeparator );
@@ -109,4 +134,19 @@ public String doWrite(Chunk<? extends T> items) {
109134 return lines .toString ();
110135 }
111136
137+ private boolean reopen (File file ) throws IOException {
138+ long length = file .length ();
139+ // try to delete JSON_OBJECT_SEPARATOR + lineSeparator + JSON_ARRAY_STOP
140+ long pos = length - (2 + this .lineSeparator .length ());
141+ if (pos <= 0 ) {
142+ return false ;
143+ }
144+ try (RandomAccessFile raf = new RandomAccessFile (file , "rw" )) {
145+ raf .setLength (pos );
146+ // file content is not empty or empty JSON array
147+ // (JSON_ARRAY_START + 2 * lineSeparator + JSON_ARRAY_STOP + lineSeparator)
148+ return length > 2 + 3L * this .lineSeparator .length ();
149+ }
150+ }
151+
112152}
0 commit comments