
개요
직렬화와 역직렬화는 객체를 저장, 전송, 재구성할 수 있게 한다. 데이터 베이스에 객체를 저장하거나, 네트워크를 통해 객체를 전송하거나, 메모리에 객체를 캐싱하는 등 다양한 방법으로 활용된다. 프로그래밍에서 객체로 다른 시스템으로 데이터를 주고 받는 과정이 많기 때문에 중요하다.
직렬화
직렬화는 객체의 상태를 바이트 스트림으로 변환하는 프로세스 이다. 이 바이트 스트림이 파일에 저장되거나, 네트워크를 통해 전송되거나, 데이터베이스에 저장되는 것이다.
직렬화는 바이너리 형식으로만 가능한 것은 아니고, JSON, XML과 같은 다양한 형식으로 직렬화가 가능하다. 하지만, 바이너리 형식이 성능상 읽고 쓰는 것이 더 빠르기 때문에 주로 사용된다.
역직렬화
역직렬화는 직렬화의 역과정이다. 바이트 스트림을 가져와 다시 객체로 변환하는 것이다. Java에서는 ObjectInputStream 클래스를 사용하여 바이너리 형식을 역직렬화할 수 있으며 Jackson 라이브러리를 사용하여 JSON 형식으로 파싱할 수 있다.
고려사항 및 단점
성능
객체의 크기가 크거나 복잡한 경우 컴퓨팅 비용의 문제가 있을 수 있다. 객체를 바이트로 변환하고 다시 객체로 변환하는 과정은 시간, 리소스의 문제로 시스템 성능에 영향을 줄 수 있다.
플랫폼 및 프로그래밍 언어 종속성
직렬화와 역직렬화는 플랫폼 및 프로그래밍 언어에 따라 달라질 수 있기에, 호환성 문제를 일으킬 수 있다.
버전 관리
직렬화된 데이터 형식의 변경이 일어나면 이전 버전의 데이터를 올바르게 역직열화 하지 못하는 경우가 발생할 수 있다.
직렬화 불가능한 객체
파일 서술자, 네트워크 소켓 같은 리소스를 담고 있는 객체는 직렬화 할 수 없을 수 있다.
보안
악의적인 바이트 스트림은 프로그램의 취약성을 악용할 수 있다. 검증된 라이브러리를 사용하고, 신뢰할 수 있는 소스의 데이터만 역직렬화하는 것이 좋다.
가독성
직렬화된 데이터는 가독성이 떨어지므로 데이터 전송, 저장 중에 문제가 발생하면 해결하거나 디버깅이 힘들다.
자바에서의 직렬화 실습
객체 생성
Serializable 를 상속받아 구현하면 직렬화 할 수 있다. 하지만, 이 상태의 경우 이클립스(IDE)에서는 “The serializable class user does not declare a static final serialVersionUID field of type long” 라는 경고가 뜨게 된다.
package serialize;
import java.io.Serializable;
public class user implements Serializable {
private String id;
private String name;
transient String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
serialVersionUID
UID는 unique identifier의 약자로 고유 식별자라는 뜻이므로, serialVersionUID는 직렬화 버전 고유 식별자라는 뜻이다. 정확한 내용을 살펴보기 위해 jhttps://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html 를 참조해보면 관련된 내용이 이렇게 작성되어 있다.
The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender’s class, then deserialization will result in an
InvalidClassException
. A serializable class can declare its own serialVersionUID explicitly by declaring a field named"serialVersionUID"
that must be static, final, and of typelong
:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpectedInvalidClassException
s during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use theprivate
modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.
내용에 나와 있듯 serialVersionUID는 직렬화 가능한 클래스를 관리하기 위한 고유 버전 번호이다. 역직렬화 과정에서 serialVersionUID가 일치하지 않으면 InvalidClassException
에러가 발생하게 된다. 만약 serialVersionUID를 선언하지 않는다고 해서 직렬화, 역직렬화가 불가능한 것은 아니다. 다만 계산된 serialVersionUID는 클래스에 변경사항이 발생하면 serialVersionUID값이 변경될 수 있어 역직렬화 과정에서 에러가 발생할 수 있다. 때문에 문서에 서 strongly recommended 하듯 생성하는 것이 좋다. 대부분의 IDE는 serialVersionUID를 버튼 클릭 몇 번으로 생성할 수 있다.