Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

Commit bb949ad

Browse files
committed
CSV-216 add mutator functions
if the record is already mutable, they will return the current object, otherwise a copy will be made using private CSVMutableRecord subclass. The method mutable() and immutable() can be used to ensure either semantics.
1 parent c290f13 commit bb949ad

2 files changed

Lines changed: 132 additions & 10 deletions

File tree

src/main/java/org/apache/commons/csv/CSVMutableRecord.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,19 @@
1919

2020
import java.util.Map;
2121

22-
public final class CSVMutableRecord extends CSVRecord {
22+
/**
23+
* A mutable version of CSVRecord
24+
* <p>
25+
* As mutation is generally done within the parent {@link CSVRecord}, this
26+
* package-private class just includes more efficient versions of
27+
* mutator functions, bypassing the need to make copies
28+
* (except in {@link #immutable()}).
29+
* <p>
30+
* To enable generating CSVMutableRecord by default, set
31+
* {@link CSVFormat#withMutableRecords(boolean)} to <code>true</code>.
32+
*
33+
*/
34+
final class CSVMutableRecord extends CSVRecord {
2335

2436
private static final long serialVersionUID = 1L;
2537

@@ -29,13 +41,25 @@ public final class CSVMutableRecord extends CSVRecord {
2941
}
3042

3143
@Override
32-
public void put(int index, String value) {
33-
super.put(index, value);
44+
public CSVMutableRecord withValue(int index, String value) {
45+
super.put(index, value);
46+
return this;
3447
}
35-
48+
3649
@Override
37-
public void put(String name, String value) {
38-
super.put(name, value);
50+
public CSVMutableRecord withValue(String name, String value) {
51+
super.put(name, value);
52+
return this;
53+
}
54+
55+
@Override
56+
public CSVRecord withComment(String comment) {
57+
this.comment = comment;
58+
return this;
59+
}
60+
61+
@Override
62+
boolean isMutable() {
63+
return true;
3964
}
40-
4165
}

src/main/java/org/apache/commons/csv/CSVRecord.java

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ public class CSVRecord implements Serializable, Iterable<String> {
3636

3737
private final long characterPosition;
3838

39-
/** The accumulated comments (if any) */
40-
private final String comment;
39+
/** The accumulated comments (if any)
40+
*
41+
* package-private so it can be mutated by {@link CSVMutableRecord}
42+
*/
43+
String comment;
4144

4245
/** The column name to index mapping. */
4346
private final Map<String, Integer> mapping;
@@ -181,6 +184,28 @@ public boolean hasComment() {
181184
return comment != null;
182185
}
183186

187+
/**
188+
* Return an immutable CSVRecord.
189+
* <p>
190+
* Immutable records have fixed values and are thus thread-safe.
191+
* <p>
192+
* If this record is already immutable, it will be returned directly,
193+
* otherwise a copy of its current values will be made.
194+
* <p>
195+
* Use {@link #mutable()} or {@link #withValue(int, String)} to get a mutable CSVRecord.
196+
*
197+
* @return Am immutable CSVRecord
198+
*/
199+
public CSVRecord immutable() {
200+
if (isMutable()) {
201+
// Subclass is probably CSVMutableRecord, freeze values
202+
String[] frozenValue = Arrays.copyOf(values, values.length);
203+
return new CSVRecord(frozenValue, mapping, comment, recordNumber, characterPosition);
204+
} else {
205+
return this;
206+
}
207+
}
208+
184209
/**
185210
* Checks whether a given column is mapped, i.e. its name has been defined to the parser.
186211
*
@@ -191,7 +216,11 @@ public boolean hasComment() {
191216
public boolean isMapped(final String name) {
192217
return mapping != null && mapping.containsKey(name);
193218
}
194-
219+
220+
boolean isMutable() {
221+
return false;
222+
}
223+
195224
/**
196225
* Checks whether a given columns is mapped and has a value.
197226
*
@@ -212,6 +241,28 @@ public boolean isSet(final String name) {
212241
public Iterator<String> iterator() {
213242
return toList().iterator();
214243
}
244+
245+
/**
246+
* Return a mutable CSVRecord.
247+
* <p>
248+
* Mutable records have more efficient implementations of
249+
* {@link #withValue(int, String)} and {@link #withValue(String, String)}
250+
* for when multiple modifications are to be done on the same record.
251+
* <p>
252+
* If this record is already mutable, it will be returned directly, otherwise
253+
* a copy of its values will be made for the new mutable record.
254+
* <p>
255+
* Use {@link #immutable()} to freeze a mutable CSVRecord.
256+
*
257+
* @return A mutable CSVRecord
258+
*/
259+
public CSVRecord mutable() {
260+
if (isMutable()) {
261+
return this;
262+
}
263+
String[] newValues = Arrays.copyOf(values, values.length);
264+
return new CSVMutableRecord(newValues, mapping, comment, recordNumber, characterPosition);
265+
}
215266

216267
void put(final int index, String value) {
217268
values[index] = value;
@@ -286,5 +337,52 @@ public String toString() {
286337
String[] values() {
287338
return values;
288339
}
340+
341+
/**
342+
* Return a CSVRecord with the given column value set.
343+
*
344+
* @param name
345+
* the name of the column to set.
346+
* @param value
347+
* The new value to set
348+
* @throws IllegalStateException
349+
* if no header mapping was provided
350+
* @throws IllegalArgumentException
351+
* if {@code name} is not mapped or if the record is inconsistent
352+
* @return A mutated CSVRecord
353+
*/
354+
public CSVRecord withValue(String name, String value) {
355+
CSVRecord r = mutable();
356+
r.put(name, value);
357+
return r;
358+
}
359+
360+
/**
361+
* Return a CSVRecord with the given column value set.
362+
*
363+
* @param index
364+
* the column to be retrieved.
365+
* @param value
366+
* The new value to set
367+
* @return A mutated CSVRecord
368+
*/
369+
public CSVRecord withValue(int index, String value) {
370+
CSVRecord r = mutable();
371+
r.put(index, value);
372+
return r;
373+
}
374+
375+
/**
376+
* Return a CSVRecord with the given comment set.
377+
*
378+
* @param comment
379+
* the comment to set, or <code>null</code> for no comment.
380+
* @return A mutated CSVRecord
381+
*/
382+
public CSVRecord withComment(String comment) {
383+
CSVRecord r = mutable();
384+
r.comment = comment;
385+
return r;
386+
}
289387

290388
}

0 commit comments

Comments
 (0)