포스트

Serialization and Deserialization

직렬화(serialization)는 객체의 상태를 바이트 스트림으로 바꾸는 과정이고, 역직렬화(deserialization)는 그 바이트 스트림에서 객체를 다시 만드는 과정이다. 메모리 안에만 있던 객체를 파일에 저장하거나 네트워크로 보내려면 정해진 형식의 바이트로 바꿔야 하기 때문에 필요하다. 게임을 멈췄다가 다시 시작할 때 멈춘 지점부터 이어지는 것도 상태를 저장하고 복원하는 같은 원리다 (Codementor).


Java의 직렬화

Java에서는 클래스가 java.io.Serializable을 구현하면 직렬화할 수 있다. 이 인터페이스에는 메서드도 필드도 없고, 직렬화 가능하다는 의미를 표시하는 역할만 한다. 직렬화 가능한 클래스의 하위 타입도 모두 직렬화 가능하다 (Javadoc).

실제 변환은 ObjectOutputStream.writeObject()와 ObjectInputStream.readObject()가 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private transient String password; // 직렬화에서 제외

    User(String name, String password) {
        this.name = name;
        this.password = password;
    }
}

// 직렬화
try (ObjectOutputStream out = new ObjectOutputStream(
        new BufferedOutputStream(new FileOutputStream("user.ser")))) {
    out.writeObject(new User("polynomeer", "secret"));
}

// 역직렬화
try (ObjectInputStream in = new ObjectInputStream(
        new BufferedInputStream(new FileInputStream("user.ser")))) {
    User user = (User) in.readObject(); // password는 null
}

transient를 붙인 필드는 직렬화되지 않고, 역직렬화하면 타입의 기본값(참조 타입은 null)으로 채워진다. 비밀번호처럼 저장하면 안 되는 값에 쓴다.


serialVersionUID

역직렬화할 때 JVM은 보낸 쪽과 받는 쪽이 직렬화 관점에서 호환되는 클래스를 가졌는지 serialVersionUID로 확인한다. 값이 다르면 InvalidClassException이 발생한다. 선언하지 않으면 클래스 구조에서 기본값을 계산하는데, 이 계산은 컴파일러 구현에 따라 달라질 수 있는 세부 사항에 민감하다. 그래서 Javadoc은 enum을 제외한 모든 직렬화 가능 클래스가 값을 명시적으로 선언하고, 가능하면 private으로 둘 것을 강하게 권한다.


주의할 점

  • 신뢰할 수 없는 데이터의 역직렬화는 본질적으로 위험하다. Javadoc은 이를 피해야 하며, 받는다면 Secure Coding Guidelines의 기준으로 검증하라고 경고한다. 외부와 주고받는 데이터에는 JSON 같은 데이터 형식을 쓰는 편이 안전하다.
  • 직렬화 가능한 클래스가 직렬화 불가능한 클래스를 상속하면, 역직렬화 때 가장 가까운 직렬화 불가능 상위 클래스의 인자 없는 생성자로 그 상위 클래스의 필드를 초기화한다. 이 생성자에 접근할 수 없으면 역직렬화가 실패한다.
  • 직렬화 형식을 직접 제어해야 하면 writeObject, readObject, writeReplace, readResolve를 정해진 시그니처로 구현한다.
  • 필드를 추가하거나 지우면 이미 저장된 바이트와의 호환성이 깨질 수 있다. 오래 보관하는 데이터라면 클래스 변경이 직렬화 형식 변경이기도 하다는 점을 염두에 둔다.
참고한 자료외부 출처 2

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다