Проблема с сериализацией и десериализацией экземпляров классов Singleton с полями ArrayList - PullRequest
0 голосов
/ 16 января 2019

В настоящее время я пишу Java-приложение, которое использует шаблон Singleton и сериализацию. У меня есть выделенный класс сериализатора, который сериализует и десериализует объект в заданный путь к файлу и из него. Один из моих объектов сериализован и десериализован без проблем: я делаю некоторые изменения в состоянии моего приложения, пока оно открыто, затем закрываю приложение, и эти изменения остаются, когда я снова открываю его. Тем не менее, это не работает с другим моим объектом, хотя, насколько я могу судить, между ними нет существенной разницы, которая должна быть причиной этого.

Вот код для моего класса Serialiser:

public static Boolean serialise(Object target, String filePath){
    try (FileOutputStream fileOut = new FileOutputStream(filePath);
        ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);){

        objectOut.writeObject(target);
        return true;
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Serialiser.class.getName()).log(Level.SEVERE, null, ex);
        return false;
    } catch (IOException ex) {
        Logger.getLogger(Serialiser.class.getName()).log(Level.SEVERE, null, ex);
        return false;
    }
}

public static Object deserialise(String filePath){
    try (FileInputStream fileIn = new FileInputStream(filePath);
        ObjectInputStream objectIn = new ObjectInputStream(fileIn);){
        Object readObject = objectIn.readObject();
        return readObject;
    } catch (IOException | ClassNotFoundException ex) {
        Logger.getLogger(Serialiser.class.getName()).log(Level.SEVERE, null, ex);
        return null;
    }
}

А вот соответствующий код для моих объектов. Во-первых, тот, который работает:

public class AccountManager implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final String FILE_PATH = "data//account_manager.ser";

    private static AccountManager instance;
    private ArrayList<Account> accounts = null;

    private AccountManager(){
        accounts = new ArrayList<>();
    }

    public static AccountManager getInstance(){
        if (instance == null){
            instance = (AccountManager)Serialiser.deserialise(FILE_PATH);
            if (instance == null){
                instance = new AccountManager();
                Serialiser.serialise(instance, FILE_PATH);
            }
        }
        return instance;
    }

А теперь тот, который не работает:

public class MessageManager implements Serializable {

private static final long serialVersionUID = 1L;
private static final String FILE_PATH = "data//message_manager.ser";

private static MessageManager instance = null;
private ArrayList<Message> messages = null;

private MessageManager(){
    messages = new ArrayList<>();
}

public static MessageManager getInstance(){
    if (instance == null){
        instance = (MessageManager)Serialiser.deserialise(FILE_PATH);
        if (instance == null){
            instance = new MessageManager();
            Serialiser.serialise(instance, FILE_PATH);
        }
    }
    return instance;
}

По сути, оба класса работают одинаково: они хранят список объектов определенного типа и обеспечивают доступ и выполняют операции с содержимым их соответствующих списков. При обращении к экземпляру Singleton классов он проверяет, может ли он десериализовать экземпляр из файла. Если это невозможно, он создает новый экземпляр и сериализует его. Опять же, это работает для одного, AccountManager, но не для другого, MessageManager. То есть, если создать новый объект Account и сохранить его с помощью AccountManager во время работы приложения, он все равно останется, если я перезапущу приложение. То же самое не относится к объектам MessageManager и Message.

При создании новой учетной записи экземпляр и, возможно, связанные с ним поля, т. Е. Список учетных записей сериализуются.

public Account createAccount(String password, String givenName, String surname, String address, Gender gender, LocalDate dateOfBirth){
        String id = IDGenerator.getInstance().generateID(AccountType.PATIENT, accounts);
        Account createdAccount = null;

        if (id != null){
            createdAccount = new PatientAccount(id, password, givenName, surname, address, gender, dateOfBirth);
            if (createdAccount != null){
                accounts.add(createdAccount);
                Serialiser.serialise(instance, FILE_PATH);
            }
            return createdAccount;
        }
        return null;
    }

В MessageManager, когда добавляется новый экземпляр Message, его список и экземпляр, а также, предположительно, его список, сериализуются:

public Boolean sendMessage(Message message){
    if (messages.add(message)){
        Serialiser.serialise(instance, FILE_PATH);
        return true;
    }
    return false;
}

И Учетная запись, и Сообщение поддерживают Serializable, и оба имеют serialVersionUID. Я не получаю никаких исключений NotSerializable.

Любая помощь в решении этой проблемы будет принята с благодарностью. При необходимости я могу предоставить больше кода моего приложения.

1 Ответ

0 голосов
/ 16 января 2019

Мне удалось решить мою проблему.Моя проблема была в другой части моего приложения.По сути, я полагал, что MessageManager не был сериализован, потому что я не мог получить данные, которые я ожидал получить от него.Оказывается, проблема была в методе, который возвращал данные: я использовал ссылку на объект, чтобы определить, какие данные вернуть.Конечно, десериализация создает новые экземпляры, поэтому после воссоздания моих объектов я больше не смог получить доступ к данным, идентифицированным старым экземпляром.

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

Спасибо всем, кто посмотрел на мой вопрос и / или попытался ответить на него.

...