Skip to content

Commit 40b7cd6

Browse files
committed
docs(website): add example for interpreting empty fields as null values
1 parent 0392eb8 commit 40b7cd6

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: Reading null values
3+
---
4+
5+
import SourceExample from '../../../../components/SourceExample.astro';
6+
7+
The concept of **null values** is not part of the CSV standard (per [RFC 4180](https://datatracker.ietf.org/doc/html/rfc4180)).
8+
9+
In some situations, however, it is necessary to interpret certain fields as null values and differentiate them from empty fields.
10+
One common example is database imports and exports, where the differentiation between null and empty fields is often required.
11+
12+
A core principle of FastCSV is to provide a null-free API, meaning that no public function ever returns null.
13+
This design choice helps prevent `NullPointerException` and makes user code more robust.
14+
15+
This feature comes with a trade-off: if you absolutely need null values, you will have to implement a workaround.
16+
17+
## Example
18+
19+
The following example demonstrates how to interpret unquoted empty fields as null values by using a custom `FieldModifier`
20+
that carries the information of `null` in a special marker String value.
21+
22+
<SourceExample filename="ExampleNamedCsvReaderWithNullFields.java"/>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package example;
2+
3+
import java.util.UUID;
4+
5+
import de.siegmar.fastcsv.reader.CsvReader;
6+
import de.siegmar.fastcsv.reader.FieldModifier;
7+
import de.siegmar.fastcsv.reader.NamedCsvRecord;
8+
import de.siegmar.fastcsv.reader.NamedCsvRecordHandler;
9+
10+
/// Example of interpreting empty, unquoted fields in a CSV as `null` values.
11+
public class ExampleNamedCsvReaderWithNullFields {
12+
13+
private static final String DATA = """
14+
firstName,middleName,lastName
15+
John,,Doe
16+
Jane,"",Smith
17+
""";
18+
19+
public static void main(final String[] args) {
20+
final NamedCsvRecordHandler callbackHandler = NamedCsvRecordHandler
21+
.of(builder -> builder.fieldModifier(new NullFieldModifier()));
22+
23+
CsvReader.builder().build(callbackHandler, DATA).stream()
24+
.map(ExampleNamedCsvReaderWithNullFields::mapPerson)
25+
.forEach(System.out::println);
26+
}
27+
28+
static Person mapPerson(final NamedCsvRecord record) {
29+
return new Person(
30+
nullable(record.getField("firstName")),
31+
nullable(record.getField("middleName")),
32+
nullable(record.getField("lastName"))
33+
);
34+
}
35+
36+
static String nullable(final String fieldValue) {
37+
return NullFieldModifier.isNull(fieldValue) ? null : fieldValue;
38+
}
39+
40+
static class NullFieldModifier implements FieldModifier {
41+
42+
/// A marker to represent null values in the CSV. The unique UUID
43+
/// ensures that it does not conflict with any actual data in the CSV.
44+
private static final String NULL_MARKER = "NULL:" + UUID.randomUUID();
45+
46+
/// {@return `NULL_MARKER` for unquoted empty fields,
47+
/// otherwise the field value itself}
48+
@Override
49+
public String modify(final long startingLineNumber, final int fieldIdx,
50+
final boolean quoted, final String field) {
51+
return !quoted && field.isEmpty() ? NULL_MARKER : field;
52+
}
53+
54+
/// {@return `true` if the field is the `NULL_MARKER`, otherwise `false`}
55+
static boolean isNull(final String field) {
56+
return NULL_MARKER.equals(field);
57+
}
58+
59+
}
60+
61+
record Person(String firstName, String middleName, String lastName) {
62+
}
63+
64+
}

0 commit comments

Comments
 (0)