EN · DE · RU · FR · ES

#1877: CSVWriter.java

projectforge-common/src/main/java/org/projectforge/common/CSVWriter.java Utility class — org.projectforge.common package, projectforge-common/src/main/java/org/projectforge/common/CSVWriter.java 176 lines · 100 code · 54 comments · 22 blank
CSV output writer that formats data into semicolon-delimited text files. Companion to CSVParser — provides a fluent builder API for writing CSV rows with proper quoting. Supports typed write() overloads for strings (with double-quote escaping), long integers, dates (ISO 8601 format), and generic objects. Configurable separator character, line ending, and date format. Used for ProjectForge data exports (address lists, timesheet exports, financial reports).

Architecture

Imports

Configuration

SettingDefaultSetter
CSV separator';' (semicolon — European convention)setCsvSeparator(char)
Line ending"\n" (Unix newline)setCr(String)
Date format"yyyy-MM-dd HH:mm:ss.SSS"setDateFormat(DateFormat)
Date timezoneUTCHardcoded in constructor

Fluent Builder API

All write() methods return this (the CSVWriter instance), enabling method chaining:

csvWriter.write("Name").write("Age").write(42L).writeEndOfLine();

Type-Specific Write Overloads

MethodFormattingQuoting
write(String s)Raw string with " escaped to "" (doubling)Always wrapped in "..." — follows RFC 4180 quoting rules
write(long value)Direct numeric output via PrintWriter.print()None — numbers are unquoted
write(Date value)Formatted via dateFormat.format() in UTCWrapped in quotes — dates may contain spaces or special chars
write(Object value)Fallback: String.valueOf(value)None — generic objects are unquoted (risky for objects with commas/quotes)

Quoting Algorithm (String Writing)

The write(String) method implements proper CSV escaping per RFC 4180:

  1. Output the separator if not the first entry in the row (managed by writeSeparator() with the firstEntry flag)
  2. Output an opening double-quote (")
  3. Iterate through each character of the string
  4. If character is a double-quote ("), output it twice ("") — the standard CSV escape sequence
  5. Output all other characters as-is
  6. Output a closing double-quote (")

Line Writing

Separator Logic (writeSeparator)

The firstEntry boolean flag tracks whether we're at the start of a line:

This is a classic state-tracking pattern for delimited output.

Integration with CSVParser

CSVWriter defines DEFAULT_CSV_SEPARATOR_CHAR = ';' as a public constant, which CSVParser references to ensure consistent default separator between reader and writer.

Comparison with Modern CSV Libraries

This implementation is intentionally minimal compared to Apache Commons CSV or OpenCSV:

The simplicity reflects its origin as a purpose-built tool for ProjectForge data export, not a general-purpose CSV library.

The write(Object) method does NOT quote the output — it calls String.valueOf(value) and writes directly. If the object's toString() returns a string containing commas, semicolons, or newlines, the resulting CSV will be malformed. This is acceptable because callers are expected to use the type-specific overloads.
Date output uses UTC timezone — dates are normalized to UTC before formatting. This is a deliberate choice for data interchange: it avoids timezone ambiguity in exports. The format "yyyy-MM-dd HH:mm:ss.SSS" is ISO 8601-like but uses a space separator instead of 'T'.

Git History

868d6abb7 2025 -> 2026
63081666f Source file headers: 2024-> 2025.
a73905c14 Fix typos in projectforge*/ directories Found via codespell
b6092df09 Copyright 2023 -> 2024
ab45d51fa Copyright 2001-2022 -> 2001-2023.
5f7ef41b8 Copyright 2021 -> 2022
ceb63e8a1 Source code header: (C) 2001-2021.
7c79f1922 Copyright of source header -> 2020.