Serialize?
JVM 메모리 - Heap or Stack - 에 있는 객체 데이터를 바이트 형태로 변환하는 기술. 이 역방향 변환을 Deserialize 라고 한다.
Java 에서의 Primitive Data Types은 별도의 처리 없이도 Serialize 가 가능하다. 다만 Object 형식의 객체는 java.io.Serializable 을 구현해야 Serialize 대상이 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13
| import java.io.Serializable;
public class Sleep implements Serializable { private int duration;
public Sleep(int duration) { this.duration = duration; } }
|
Serialize 에는 java.io.ObjectOutputStream 을 사용한다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Sleep sleep = new Sleep(1000);
try ( ByteArrayOutputStream arraySerializer = new ByteArrayOutputStream(); ObjectOutputStream objectSerializer = new ObjectOutputStream(arraySerializer); ) { objectSerializer.writeObject(sleep);
persistSerialized(arraySerializer.toByteArray()); } catch(IOException serializeFailed) { handleSerializeFail(serializeFailed); }
|
serialVersionUID
Serialize/Deserialize 간에 Serialize 대상의 고유 번호 표시이다.
Serialize 인터페이스를 상속한 클래스는 가급적 이 번호도 추가하는게 좋다.
serialVersionUID
는 명시적인 선언 없이도 자동으로 생성되나 없을 경우 특정 알고리즘을 사용 하여 클래스의 해시값으로 지정된다.
Serialize 는 상당히 까다롭게 동작한다.
클래스가 같더라도 Serialize/Deserialize 시에 serialVersionUID 값이 다르다면 InvalidClassException 이 던져진다
자동 생성된 serialVersionUID 는 클래스의 해시값이기에 클래스 구조에 변화가 생기면 다를 수밖에 없다. 또한, 명시적인 선언이 있어도 데이터 타입이 변경될 경우 오류가 발생한다. 이 경우에는 InvalidClassException 이 던져진다.
Pre-Process Methods
Serialize/Deserialize 중 Singleton 등의 인스턴스 제한, 알수없는 데이터에 대한 Deserialize 검증 등의 특수한 처리가 필요할 경우가 종종 있다.
이럴 경우에 대해 Serialize 전처리 메서드들이 준비되어 있다
1 2 3 4 5
| void writeObject(java.io.ObjectOutputStream out) throws IOException void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; void readObjectNoData() throws ObjectStreamException; Object writeReplace() throws ObjectStreamException; Object readResolve() throws ObjectStreamException;
|
writeObject/readObject
해당 class 에 위의 전처리 메서드를 구현할 경우 Serialize/Deserialize 시에 호출된다. 보통은 해당 클래스의 상태에 전처리를 할때 사용한다.
특정 데이터를 writeObject 시에 추가한뒤 readObject 시에 다시 읽거나, 외부 시스템으로부터 받은 수상한 데이터에 대한 방어 목적으로도 사용할 수 있다. 객체에 특정 서명을 추가하거나 해서 어느정도의 보안도 적용 가능해진다.
만일 이 메서드에서 NotSerializableException 을 던지게 되면 Serialize 가 불가능하게 된다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class Sleep implements Serializable {
private int duration; private transient String place;
public Sleep(int duration, String place) { this.duration = duration; this.place = place; }
private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeObject(this.place); }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.place = (String) in.readObject(); } }
|
readObjectNoData
https://stackoverflow.com/questions/7445217/java-when-to-add-readobjectnodata-during-serialization/7445415
writeReplace/readResolve
이 메서드를 구현해서 원래 Serialize/Deserialize 대상 객체를 변경할 수 있다.
직렬화에 대한 프록시 기능이나 인스턴스 수 제한에 유용하다.
링크 하나 공유한다.
Serialization and magic methods