Почему Джексон переносит строку, содержащую запятую, при перестройке схемы конфигурации для построения строки записи для CSV? - PullRequest
0 голосов
/ 23 октября 2019

Я получаю данные из репозитория и помещаю их в CSV. Для построения рекордной линии я использую Джексона. Моя цель - обернуть поле (тип String) двойными кавычками, если значение этого поля содержит запятую. Поэтому выходные данные должны выглядеть следующим образом:

some-uuid-value, некоторая строка без запятой, SOMETHING, 123456, www.some.url и т. Д.
some-uuid-value, "некоторая строка, но с запятой", SOMETHING, 123456, www.some.url и т. д.
some-uuid-value, некоторая строка без запятой, SOMETHING, 123456, www. some.url и т. д.

Я придумал этот код:

private String toCsvString(EntityCsvRecord entity) {

        CsvMapper mapper = new CsvMapper();
        CsvSchema schema = mapper.schemaFor(EntityCsvRecord.class).withoutQuoteChar();

        if (entity.getName() == null) {
            entity.setName("");
        }

        if (entity.getName().contains(",")) {
            String columnName = "name";
            int nameColumnIndex = schema.column(columnName).getIndex();
            schema = mapper
                .configure(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING, true)
                .schemaFor(EntityCsvRecord.class)
                .rebuild()
                .replaceColumn(nameColumnIndex, new CsvSchema.Column(nameColumnIndex, columnName))
                .build();
        }

        try {
            return mapper.writer(schema).writeValueAsString(entity);
        } catch (Exception e) {
            ...
        }
    }

Однако я не понимаю, почему он работает так, я не смог найти спускподсказки в документации.

Может ли кто-нибудь пролить свет на эту тайну?

1 Ответ

0 голосов
/ 24 октября 2019

Весь трюк в том, что вы включаете функцию CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING . Из документации:

Функция, которая определяет объем работы, выполняемой перед определением того, что для значения столбца требуется заключить в кавычки: при значении true полная проверка выполняется только в тех случаях, когда это строго необходимо;но при значении false выполняется более быстрая, но более консервативная проверка, и, возможно, цитирование используется для значений, которые могут в ней не нуждаться. Компромиссы в основном заключаются между оптимальным / минимальным цитированием (true) и более быстрой обработкой (false). Более быстрая проверка включает в себя только проверку первых N символов значения, а также возможные более слабые проверки.

Тем не менее, обратите внимание, что независимо от настройки все значения, которые должны быть заключены в кавычки, будут следующими: просто при значении false другие значения также могут быть заключены в кавычки (чтобы избежать необходимости делать более дорогие проверки).

Значение по умолчанию - false для «свободной» (приблизительной, консервативной) проверки.

Все остальные конфигурации для схемы и преобразователя можно удалить, и они будут работать аналогичным образом. Вы можете упростить его до следующего кода:

class CsvEntityGenerator {

    private final CsvMapper mapper;
    private final CsvSchema schema;

    public CsvEntityGenerator(Class clazz) {
        mapper = new CsvMapper();
        mapper.enable(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING);

        schema = mapper.schemaFor(clazz).withNullValue("");
    }

    public String toCsvString(Object entity) throws IOException {
        return mapper.writer(schema).writeValueAsString(entity);
    }
}

И простое использование:

CsvEntityGenerator gen = new CsvEntityGenerator(EntityCsvRecord.class);
System.out.print(gen.toCsvString(new EntityCsvRecord("Na,me")));
System.out.print(gen.toCsvString(new EntityCsvRecord(null)));
System.out.print(gen.toCsvString(new EntityCsvRecord("Name")));

Отпечатки:

8b572b1b-17c1-429d-887b-ec9af1c30d05,"Na,me",SOMETHING,123456,www.some.url
e86eacb1-d45e-4614-91bb-45f0d8840ea9,,SOMETHING,123456,www.some.url
e9627c32-6736-44a5-8eb2-7d153f86af20,Name,SOMETHING,123456,www.some.url

Как видите, мы создаем CsvMapper и CsvSchema только один раз и повторно используем его, когда мы хотим сериализовать сущности. Это гораздо более быстрый подход.

...