Java Serialization 2013 — различия между версиями

Материал из SEWiki
Перейти к: навигация, поиск
(1. TestFrame)
(1. Serialization.java (основная часть))
Строка 7: Строка 7:
  
 
<source lang="java">
 
<source lang="java">
 +
import java.io.Externalizable;
 +
import java.io.FileInputStream;
 +
import java.io.FileNotFoundException;
 +
import java.io.FileOutputStream;
 +
import java.io.IOException;
 +
import java.io.InputStream;
 +
import java.io.ObjectInput;
 +
import java.io.ObjectInputStream;
 +
import java.io.ObjectOutput;
 +
import java.io.ObjectOutputStream;
 +
import java.io.ObjectStreamField;
 +
import java.io.OutputStream;
 +
import java.io.Serializable;
 +
import java.util.ArrayList;
 +
import java.util.List;
 +
 +
import org.junit.Test;
 +
 +
 +
 +
/**
 +
* Лекция о сериализации в Java.
 +
*/
 +
@SuppressWarnings({"unused"})
 +
public class Serialization {
 +
 +
/****Введение****/
 +
 +
/**
 +
*
 +
* Сериализация -- запись объекта в байтовый поток.
 +
*
 +
* Десереализация -- CO.
 +
*
 +
* Все в пакете java.io
 +
*
 +
* Мотивация:
 +
* 1. dump (ex. JavaBeans persistence)
 +
* 2. RMI
 +
*/
 +
class Point {
 +
double x;
 +
double y;
 +
}
 +
 +
 +
 +
 +
//move to Point1.java and SimplePointTest.java
 +
 +
 +
/****Процесс сериализации****/
 +
 +
/**
 +
* В сериализации участвуют ВСЕ достижимые объекты.
 +
*
 +
* Запись:
 +
* 1. Запись предка (если он сериализуем)
 +
* 2. Запись полей (если они сериализуемы)
 +
*
 +
* Циклические зависимости корректно обрабатываются автоматически.
 +
*
 +
* Чтение:
 +
* 1. Выделение памяти под объект
 +
* 2. Чтение предка
 +
* 3. Чтение полей
 +
*/
 +
 +
/**
 +
* Все поля должны быть сериализуемы!
 +
*/
 +
@SuppressWarnings("serial")
 +
class Polygon implements Serializable {
 +
 +
List<Point3> vertices = new ArrayList<>();
 +
 +
}
 +
 +
 +
/**
 +
* Пока все просто, но впечатление обманчиво!
 +
*
 +
* 1. Внутреннее представление становится частью интерфейса
 +
* Инкапсуляция летит к чертям!
 +
* 2. Увеличивает объемы тестирования новых версий
 +
* 3. Дополнительный конструктор!
 +
* Необходимо обеспечивать все инварианты
 +
* Некоторые дыры в безопасности
 +
* 4. Все потомки становятся сериализуемыми!
 +
*/
 +
 +
/****Управление сериализацией****/
 +
 +
/**
 +
* Serial version UID (stream unique identifier)
 +
*
 +
* Применяется для обеспечения совместимости, когда версии класса изменяются
 +
*
 +
* По-умолчанию автоматически создается на основе имени, интерфейсов,
 +
* public и protected полей
 +
*
 +
* В случае несовпадения -- InvalidClassException
 +
*
 +
*/
 +
class Point2 implements Serializable {
 +
private static final long serialVersionUID = 4889340678034881968L;
 +
 +
double x;
 +
double y;
 +
}
 +
 +
 +
/**
 +
* Модификатор transient.
 +
* Исключает поле из процесса сериализации.
 +
* Примеры:
 +
* 1. Избыточная информация (предподсчитанные значения)
 +
* 2. Несериализуемые поля
 +
*
 +
*/
 +
class Point3 implements Serializable {
 +
private static final long serialVersionUID = 4889340678034881968L;
 +
 +
double x;
 +
double y;
 +
transient int precomputedHash;
 +
 +
public int hashCode() {
 +
return precomputedHash;
 +
}
 +
 +
private int countHash() {
 +
//some very involved procedure
 +
return 0;
 +
}
 +
 +
Point3(double x, double y) {
 +
this.x = x;
 +
this.y = y;
 +
precomputedHash = countHash();
 +
}
 +
}
 +
 +
/**
 +
* Настраиваемая сериализация
 +
* Методы
 +
* readObject(ObjectInputStream in) -- должен прочесть состояние из потока
 +
* writeObject(ObjectOutputStream out) -- должен записать состояние в поток
 +
*
 +
* Процесс чтения
 +
* 1. Выделение памяти
 +
* 2. Вызов readObject
 +
 +
*/
 +
class Point4 implements Serializable {
 +
private static final long serialVersionUID = 4889340678034881968L;
 +
 +
double x;
 +
double y;
 +
 +
transient int precomputedHash;
 +
 +
public int hashCode() {
 +
return precomputedHash;
 +
}
 +
 +
private int countHash() {
 +
//some very involved procedure
 +
return 0;
 +
}
 +
 +
Point4(double x, double y) {
 +
this.x = x;
 +
this.y = y;
 +
precomputedHash = countHash();
 +
}
 +
 +
/*
 +
* Отвечает только за запись полей ЭТОГО класса, не предка и не потомка!
 +
*/
 +
private void writeObject(ObjectOutputStream s) throws IOException {
 +
/*
 +
* Реализует стандартный механизм сериализации.
 +
* Может вызываться только из writeObject, иначе NotActiveException
 +
*/
 +
s.defaultWriteObject();
 +
}
 +
 +
//отвечает только за чтение полей ЭТОГО класса, не предка и не потомка!
 +
private void readObject(ObjectInputStream s) throws IOException,
 +
ClassNotFoundException {
 +
/*
 +
* Реализует стандартный механизм десериализации.
 +
* Может вызываться только из readObject, иначе NotActiveException
 +
*/
 +
s.defaultReadObject();
 +
//восстановление инвариантов
 +
precomputedHash = countHash();
 +
}
 +
}
 +
 +
 +
 +
 +
 +
//move to Point5.java
 +
 +
 +
 +
 +
 +
 +
/**
 +
* Сериализация с несериализуемым предком.
 +
*
 +
* Если хочется отнаследовать сериализуемый класс от
 +
* несериализуемого предка, то могут быть проблемы...
 +
*
 +
* Формальное требование одно -- предок должен иметь
 +
* конструктор по-умолчанию.
 +
*
 +
* Но только ли?!
 +
*/
 +
class NonSerializablePoint {
 +
private double x;
 +
private double y;
 +
 +
protected double getX() {return x;}
 +
 +
protected double getY() {return y;}
 +
 +
protected void init(double x, double y) {
 +
this.x = x;
 +
this.y = y;
 +
}
 +
 +
protected NonSerializablePoint() {}
 +
 +
public NonSerializablePoint(double x, double y) {
 +
init(x, y);
 +
}
 +
}
 +
 +
// Serializable subclass of nonserializable stateful class
 +
class ColoredPoint extends NonSerializablePoint implements Serializable {
 +
private int color;
 +
 +
// Конструктор использует обычный механизм
 +
public ColoredPoint(double x, double y, int color) {
 +
super(x, y);
 +
this.color = color;
 +
}
 +
 +
private void readObject(ObjectInputStream s) throws IOException,
 +
ClassNotFoundException {
 +
s.defaultReadObject();
 +
// Manually deserialize and initialize superclass state
 +
double x = s.readDouble();
 +
double y = s.readDouble();
 +
init(x, y);
 +
}
 +
 +
private void writeObject(ObjectOutputStream s) throws IOException {
 +
s.defaultWriteObject();
 +
// Manually serialize superclass state
 +
s.writeDouble(getX());
 +
s.writeDouble(getY());
 +
}
 +
 +
private static final long serialVersionUID = 1856835860954L;
 +
}
 +
 +
 +
 +
/**
 +
* Externalizable
 +
*
 +
* Сериализация "в ручную"
 +
 +
* void readExternal(ObjectInput in)
 +
* void writeExternal(ObjectOutput out)
 +
*
 +
* Должен быть конструктор по-умолчанию
 +
*
 +
* Чтение: вызов конструктора по-умолчанию, вызов readExternal
 +
*/
 +
class Point6 implements Externalizable {
 +
private double x;
 +
private double y;
 +
 +
Point6(double x, double y) {
 +
this.x = x;
 +
this.y = y;
 +
}
 +
 +
@Override
 +
public void writeExternal(ObjectOutput out) throws IOException {
 +
out.writeDouble(x);
 +
out.writeDouble(y);
 +
}
 +
@Override
 +
public void readExternal(ObjectInput in) throws IOException,
 +
ClassNotFoundException {
 +
this.x = in.readDouble();
 +
this.y = in.readDouble();
 +
}
 +
}
 +
 +
/**
 +
* "Подмена" сериализуемого объекта.
 +
*
 +
* Когда вместо самого объекта сериализуется его альтернативное представление
 +
* в виде другого объекта некоторого (возможно того же самого) сериализуемого класса.
 +
*
 +
* Object writeReplace() -- какой объект записать вместо данного
 +
* Object readResolve() -- какой объект восстановить вместо прочитанного
 +
*
 +
* Реализуются у разных классов!!!
 +
*/
 +
 +
}
 +
 
import java.io.Externalizable;
 
import java.io.Externalizable;
 
import java.io.FileInputStream;
 
import java.io.FileInputStream;

Версия 15:08, 22 мая 2013

Что почитать

1. Serialization.java (основная часть)

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;



/**
 * Лекция о сериализации в Java.
 */
@SuppressWarnings({"unused"})
public class Serialization {

	/****Введение****/
	
	/**
	 * 
	 * Сериализация -- запись объекта в байтовый поток.
	 * 
	 * Десереализация -- CO.
	 * 
	 * Все в пакете java.io
	 * 
	 * Мотивация:
	 * 	1. dump (ex. JavaBeans persistence)
	 * 	2. RMI
	 */
	class Point {
		double x;
		double y;
	}
	

	
	
	//move to Point1.java and SimplePointTest.java
	
	
	/****Процесс сериализации****/
	
	/**
	 * В сериализации участвуют ВСЕ достижимые объекты.
	 * 
	 * Запись:
	 * 	1. Запись предка (если он сериализуем)
	 * 	2. Запись полей (если они сериализуемы)
	 * 
	 * Циклические зависимости корректно обрабатываются автоматически.
	 * 
	 * Чтение:
	 * 	1. Выделение памяти под объект
	 * 	2. Чтение предка
	 * 	3. Чтение полей
	 */
	
	/**
	 * Все поля должны быть сериализуемы!
	 */
	@SuppressWarnings("serial")
	class Polygon implements Serializable {

		List<Point3> vertices = new ArrayList<>();
		
	}
	
	
	/**
	 * Пока все просто, но впечатление обманчиво!
	 * 
	 * 1. Внутреннее представление становится частью интерфейса
	 * 		Инкапсуляция летит к чертям!
	 * 2. Увеличивает объемы тестирования новых версий
	 * 3. Дополнительный конструктор! 
	 * 		Необходимо обеспечивать все инварианты
	 * 		Некоторые дыры в безопасности
	 * 4. Все потомки становятся сериализуемыми!
	 */
	
	/****Управление сериализацией****/
	
	/**
	 * Serial version UID (stream unique identifier)
	 * 
	 * Применяется для обеспечения совместимости, когда версии класса изменяются
	 * 
	 * По-умолчанию автоматически создается на основе имени, интерфейсов, 
	 * public и protected полей
	 * 
	 * В случае несовпадения -- InvalidClassException
	 * 
	 */
	class Point2 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
	}


	/**
	 * Модификатор transient.
	 * Исключает поле из процесса сериализации.
	 * Примеры:
	 * 	1. Избыточная информация (предподсчитанные значения)
	 * 	2. Несериализуемые поля
	 * 
	 */
	class Point3 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point3(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
	}
	
	/**
	 * Настраиваемая сериализация 
	 * Методы 
	 * 	readObject(ObjectInputStream in) -- должен прочесть состояние из потока 
	 * 	writeObject(ObjectOutputStream out) -- должен записать состояние в поток
	 * 
	 * Процесс чтения
	 * 	1. Выделение памяти
	 * 	2. Вызов readObject
	 *  
	 */
	class Point4 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point4(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
		
		/*
		 * Отвечает только за запись полей ЭТОГО класса, не предка и не потомка!
		 */
		private void writeObject(ObjectOutputStream s) throws IOException {
			/*
			 * Реализует стандартный механизм сериализации.
			 * Может вызываться только из writeObject, иначе NotActiveException
			 */
			s.defaultWriteObject();
		}

		//отвечает только за чтение полей ЭТОГО класса, не предка и не потомка!
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			/*
			 * Реализует стандартный механизм десериализации.
			 * Может вызываться только из readObject, иначе NotActiveException
			 */
			s.defaultReadObject();
			//восстановление инвариантов
			precomputedHash = countHash();
		}
	}


	
	
	
	//move to Point5.java
	
	
	
	
	
	
	/**
	 * Сериализация с несериализуемым предком.
	 * 
	 * Если хочется отнаследовать сериализуемый класс от 
	 * несериализуемого предка, то могут быть проблемы...
	 * 
	 * Формальное требование одно -- предок должен иметь 
	 * конструктор по-умолчанию.
	 * 
	 * Но только ли?!
	 */
	class NonSerializablePoint {
		private double x;
		private double y;
		
		protected double getX() {return x;}
		
		protected double getY() {return y;}
		
		protected void init(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		protected NonSerializablePoint() {}
		
		public NonSerializablePoint(double x, double y) {
			init(x, y);
		}
	}
	
	// Serializable subclass of nonserializable stateful class
	class ColoredPoint extends NonSerializablePoint implements Serializable {
		private int color;

		// Конструктор использует обычный механизм
		public ColoredPoint(double x, double y, int color) {
			super(x, y);
			this.color = color;
		}
		
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			s.defaultReadObject();
			// Manually deserialize and initialize superclass state
			double x = s.readDouble();
			double y = s.readDouble();
			init(x, y);
		}
		
		private void writeObject(ObjectOutputStream s) throws IOException {
			s.defaultWriteObject();
			// Manually serialize superclass state
			s.writeDouble(getX());
			s.writeDouble(getY());
		}

		private static final long serialVersionUID = 1856835860954L;
	}

	
	
	/**
	 * Externalizable
	 * 
	 * Сериализация "в ручную"
	 *  
	 * 	void readExternal(ObjectInput in)
	 * 	void writeExternal(ObjectOutput out) 
	 * 
	 * Должен быть конструктор по-умолчанию
	 * 
	 * Чтение: вызов конструктора по-умолчанию, вызов readExternal
	 */
	class Point6 implements Externalizable {
		private double x;
		private double y;

		Point6(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		@Override
		public void writeExternal(ObjectOutput out) throws IOException {
			out.writeDouble(x);
			out.writeDouble(y);
		}
		@Override
		public void readExternal(ObjectInput in) throws IOException,
				ClassNotFoundException {
			this.x = in.readDouble();
			this.y = in.readDouble();
		}
	}
	
	/**
	 * "Подмена" сериализуемого объекта.
	 * 
	 * Когда вместо самого объекта сериализуется его альтернативное представление
	 * в виде другого объекта некоторого (возможно того же самого) сериализуемого класса. 
	 * 
	 * Object writeReplace() -- какой объект записать вместо данного
	 * Object readResolve() -- какой объект восстановить вместо прочитанного
	 * 
	 * Реализуются у разных классов!!!
	 */
	
}

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;



/**
 * Лекция о сериализации в Java.
 */
@SuppressWarnings({"unused"})
public class Serialization {

	/****Введение****/
	
	/**
	 * 
	 * Сериализация -- запись объекта в байтовый поток.
	 * 
	 * Десереализация -- CO.
	 * 
	 * Все в пакете java.io
	 * 
	 * Мотивация:
	 * 	1. dump (ex. JavaBeans persistence)
	 * 	2. RMI
	 */
	class Point {
		double x;
		double y;
	}
	

	
	
	//move to Point1.java and SimplePointTest.java
	
	
	/****Процесс сериализации****/
	
	/**
	 * В сериализации участвуют ВСЕ достижимые объекты.
	 * 
	 * Запись:
	 * 	1. Запись предка (если он сериализуем)
	 * 	2. Запись полей (если они сериализуемы)
	 * 
	 * Циклические зависимости корректно обрабатываются автоматически.
	 * 
	 * Чтение:
	 * 	1. Выделение памяти под объект
	 * 	2. Чтение предка
	 * 	3. Чтение полей
	 */
	
	/**
	 * Все поля должны быть сериализуемы!
	 */
	@SuppressWarnings("serial")
	class Polygon implements Serializable {

		List<Point3> vertices = new ArrayList<>();
		
	}
	
	
	/**
	 * Пока все просто, но впечатление обманчиво!
	 * 
	 * 1. Внутреннее представление становится частью интерфейса
	 * 		Инкапсуляция летит к чертям!
	 * 2. Увеличивает объемы тестирования новых версий
	 * 3. Дополнительный конструктор! 
	 * 		Необходимо обеспечивать все инварианты
	 * 		Некоторые дыры в безопасности
	 * 4. Все потомки становятся сериализуемыми!
	 */
	
	/****Управление сериализацией****/
	
	/**
	 * Serial version UID (stream unique identifier)
	 * 
	 * Применяется для обеспечения совместимости, когда версии класса изменяются
	 * 
	 * По-умолчанию автоматически создается на основе имени, интерфейсов, 
	 * public и protected полей
	 * 
	 * В случае несовпадения -- InvalidClassException
	 * 
	 */
	class Point2 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
	}


	/**
	 * Модификатор transient.
	 * Исключает поле из процесса сериализации.
	 * Примеры:
	 * 	1. Избыточная информация (предподсчитанные значения)
	 * 	2. Несериализуемые поля
	 * 
	 */
	class Point3 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point3(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
	}
	
	/**
	 * Настраиваемая сериализация 
	 * Методы 
	 * 	readObject(ObjectInputStream in) -- должен прочесть состояние из потока 
	 * 	writeObject(ObjectOutputStream out) -- должен записать состояние в поток
	 * 
	 * Процесс чтения
	 * 	1. Выделение памяти
	 * 	2. Вызов readObject
	 *  
	 */
	class Point4 implements Serializable {
		private static final long serialVersionUID = 4889340678034881968L;

		double x;
		double y;
		
		transient int precomputedHash;
		
		public int hashCode() {
			return precomputedHash;
		}
		
		private int countHash() {
			//some very involved procedure
			return 0;
		}
		
		Point4(double x, double y) {
			this.x = x;
			this.y = y;
			precomputedHash = countHash();
		}
		
		/*
		 * Отвечает только за запись полей ЭТОГО класса, не предка и не потомка!
		 */
		private void writeObject(ObjectOutputStream s) throws IOException {
			/*
			 * Реализует стандартный механизм сериализации.
			 * Может вызываться только из writeObject, иначе NotActiveException
			 */
			s.defaultWriteObject();
		}

		//отвечает только за чтение полей ЭТОГО класса, не предка и не потомка!
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			/*
			 * Реализует стандартный механизм десериализации.
			 * Может вызываться только из readObject, иначе NotActiveException
			 */
			s.defaultReadObject();
			//восстановление инвариантов
			precomputedHash = countHash();
		}
	}


	
	
	
	//move to Point5.java
	
	
	
	
	
	
	/**
	 * Сериализация с несериализуемым предком.
	 * 
	 * Если хочется отнаследовать сериализуемый класс от 
	 * несериализуемого предка, то могут быть проблемы...
	 * 
	 * Формальное требование одно -- предок должен иметь 
	 * конструктор по-умолчанию.
	 * 
	 * Но только ли?!
	 */
	class NonSerializablePoint {
		private double x;
		private double y;
		
		protected double getX() {return x;}
		
		protected double getY() {return y;}
		
		protected void init(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		protected NonSerializablePoint() {}
		
		public NonSerializablePoint(double x, double y) {
			init(x, y);
		}
	}
	
	// Serializable subclass of nonserializable stateful class
	class ColoredPoint extends NonSerializablePoint implements Serializable {
		private int color;

		// Конструктор использует обычный механизм
		public ColoredPoint(double x, double y, int color) {
			super(x, y);
			this.color = color;
		}
		
		private void readObject(ObjectInputStream s) throws IOException,
				ClassNotFoundException {
			s.defaultReadObject();
			// Manually deserialize and initialize superclass state
			double x = s.readDouble();
			double y = s.readDouble();
			init(x, y);
		}
		
		private void writeObject(ObjectOutputStream s) throws IOException {
			s.defaultWriteObject();
			// Manually serialize superclass state
			s.writeDouble(getX());
			s.writeDouble(getY());
		}

		private static final long serialVersionUID = 1856835860954L;
	}

	
	
	/**
	 * Externalizable
	 * 
	 * Сериализация "в ручную"
	 *  
	 * 	void readExternal(ObjectInput in)
	 * 	void writeExternal(ObjectOutput out) 
	 * 
	 * Должен быть конструктор по-умолчанию
	 * 
	 * Чтение: вызов конструктора по-умолчанию, вызов readExternal
	 */
	class Point6 implements Externalizable {
		private double x;
		private double y;

		Point6(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		@Override
		public void writeExternal(ObjectOutput out) throws IOException {
			out.writeDouble(x);
			out.writeDouble(y);
		}
		@Override
		public void readExternal(ObjectInput in) throws IOException,
				ClassNotFoundException {
			this.x = in.readDouble();
			this.y = in.readDouble();
		}
	}
	
	/**
	 * "Подмена" сериализуемого объекта.
	 * 
	 * Когда вместо самого объекта сериализуется его альтернативное представление
	 * в виде другого объекта некоторого (возможно того же самого) сериализуемого класса. 
	 * 
	 * Object writeReplace() -- какой объект записать вместо данного
	 * Object readResolve() -- какой объект восстановить вместо прочитанного
	 * 
	 * Реализуются у разных классов!!!
	 */
	
}