Как сериализовать объект, который реализует Serializable, но содержит поля, которые этого не делают? - PullRequest
0 голосов
/ 24 января 2020

Указанная мной библиотека c - это библиотека Apache Commons CSV v1.8 (последняя). Я пытаюсь сериализовать объект, который содержит CSVRecord, но давайте посмотрим на его код:

public final class CSVRecord implements Serializable, Iterable<String> {
    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final long serialVersionUID = 1L;
    private final long characterPosition;
    private final String comment;
    private final long recordNumber;
    private final String[] values;
    private final CSVParser parser;

Он реализует Serializable, однако он содержит CSVParser, который НЕ сериализуем:

public final class CSVParser implements Iterable<CSVRecord>, Closeable {
    private final CSVFormat format;
    private final Map<String, Integer> headerMap;
    private final List<String> headerNames;
    private final Lexer lexer;
    private final CSVParser.CSVRecordIterator csvRecordIterator;
    private final List<String> recordList;
    private long recordNumber;
    private final long characterOffset;
    private final Token reusableToken;

Есть ли способ обойти это без изменения библиотеки, чтобы сделать это переходным полем? Это просто недосмотр авторов, или есть какой-то способ сериализации CSVRecord, который я не вижу?

Ответы [ 2 ]

1 голос
/ 24 января 2020

Отличный улов! :) Я тоже просмотрел код и не нашел способа обойти эту проблему, не касаясь кода библиотеки. Но даже у этого есть проблемы, как я вижу.

Я думаю, что причина, по которой CSVParser не Serializable, заключается в том, что он сохраняет файл открытым до завершения чтения. Если разрешено сериализацию, то это означает, что во время десериализации (возможно, в другой системе или в тот момент, когда файл больше не существует) объект по-прежнему ссылается на файл!

Таким образом, даже если вы измените код библиотеки, скажем, на удаление final из CSVParser и напишите сериализуемый подкласс или создадите parser поле transient в CSVRecord, оно все равно не будет помогите, потому что десериализованный класс не будет работать, как объяснено выше.

Следовательно, я вижу только выполнимый способ не-сериализации (ie, JSON или Map, et c. ).

0 голосов
/ 24 января 2020

Используйте transient ключевое слово java.

Переменные могут быть помечены как временные, чтобы указать, что они не являются частью постоянного состояния объекта.

Таким образом, вышеуказанный сериализуемый класс становится

public final class CSVRecord implements Serializable, Iterable<String> {
    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final long serialVersionUID = 1L;
    private final long characterPosition;
    private final String comment;
    private final long recordNumber;
    private final String[] values;
    private final transient CSVParser parser;
    ..
    ..
    ..
}
...