Как бороться с зависимыми полями при сериализации?

1

Я не понимаю общих принципов работы с зависимыми полями при сериализации классов.

Существует много шаблонов, где поля отображаются зависимыми друг от друга. Например, ниже я создаю наблюдаемую оболочку для списка в конструкторе. При создании оболочка принимает поле зависимостей и обертывает его.

Этот класс не десериализуется как в Gson и по умолчанию Java deserializer.

В Gson он вызывает конструктор по умолчанию, который сначала устанавливает связь. Но позже Gson создает новый экземпляр для члена delegate, который нарушает связь, так как observable теперь относится к устаревшему объекту.

Я не понимаю, зачем создатели Gson называют конструктор по умолчанию, если они позже отбросят его функцию? Думают ли они, что каждый класс может выдержать прямое назначение поля?

Сериализация Java по умолчанию также не работает. Они просто игнорируют переходное поле и остаются нулевыми. Конструктор не вызывается.

Я также не понимаю: если они не вызывают конструктор, то почему они не предполагают, что интерфейс Serializable имеет некоторый эквивалентный конструктор метод, который следует вызывать после десериализации?

package tests;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;

public class Try05 {

    public static class MyList implements Serializable {

        private static final long serialVersionUID = 7048098048856503023L;

        ArrayList<Integer> delegate = new ArrayList<Integer>();
        transient ObservableList<Integer> observable = FXCollections.observableList(delegate);

        public void add(int value) {
            observable.add(value);
        }

        public int sum() {
            int ans = 0;
            for (Integer i : observable) {
                ans += i.intValue();
            }
            return ans;
        }

        @Override
        public String toString() {
            return delegate.toString();
        }

    }

    public static void tryGson() throws JsonIOException, IOException {

        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().serializeNulls().setPrettyPrinting().setVersion(1.0)
                .create();

        MyList list = new MyList();

        list.add(12);
        list.add(13);

        System.out.println(String.format("list = %s, sum = %d", list.toString(), list.sum()));
        System.out.println(String.format("hash = %d", System.identityHashCode(list.delegate)));

        File file = File.createTempFile("list", ".json");

        FileWriter writer = new FileWriter(file);
        gson.toJson(list, writer);
        writer.flush();
        writer.close();

        list = gson.fromJson(new FileReader(file), MyList.class);

        list.add(14);

        System.out.println(String.format("list = %s, sum = %d", list.toString(), list.sum()));
        System.out.println(String.format("hash = %d", System.identityHashCode(list.delegate)));

    }

    public static void tryBuiltin() throws IOException, ClassNotFoundException {

        MyList list = new MyList();

        list.add(12);
        list.add(13);

        System.out.println(String.format("list = %s, sum = %d", list.toString(), list.sum()));
        System.out.println(String.format("hash = %d", System.identityHashCode(list.delegate)));

        File file = File.createTempFile("list", ".json");

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
        out.writeObject(list);
        out.flush();
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        list = (MyList) in.readObject();

        list.add(14);

        System.out.println(String.format("list = %s, sum = %d", list.toString(), list.sum()));
        System.out.println(String.format("hash = %d", System.identityHashCode(list.delegate)));

    }


    public static void main(String[] args) {

        try {

            tryGson();

            tryBuiltin();

        } catch (JsonIOException | IOException | ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }


}
Теги:
deserialization
serialization

1 ответ

1

Ваше утверждение о интерфейсе Serializable не содержащем метод, вызываемый при десериализации, неверно - есть; используя сериализацию java по умолчанию, вы можете объявить специальный метод, который будет вызываться при чтении вашего объекта. Это выглядит так:

private /* or any other access modifier */ void readObject(ObjectInputStream in) throws IOException {
    // your code here
}

В этом случае содержимое этого метода будет выглядеть так:

in.defaultReadObject(); // invoke default read
observable = FXCollections.observableList(delegate); // initialise observable

Дополнительные сведения об этом методе и другие сведения см. В спецификации класса Serializable: http://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню