Skip to content

[아이템 87] 커스텀 직렬화 형태를 고려해보라 #94

Description

@Ori-Gui

📌 [아이템 87] 커스텀 직렬화 형태를 고려해보라

✨ 핵심 내용

  • 기본 직렬화 형태는 신중히 사용해야 한다.
    • 기본 직렬화는 객체의 물리적 표현을 저장하므로, 내부 구현에 의존하게 되어 유지보수에 문제가 생긴다.
    • 변경 예정인 내부 구조가 직렬화 형태에 포함되면, 해당 구현에 영원히 발이 묶이게 된다.
  • 기본 직렬화는 객체의 논리적 상태와 물리적 상태가 같을 때에만 적합하다.
  • 불변식을 보장하고 보안 문제를 방지하기 위해 readObject() 메서드를 직접 정의해야 할 수 있다.
  • 직렬화 형태는 일종의 공개 API로 간주되므로, @serial@serialData 태그를 활용해 문서화가 필요하다.

✅ 예제 코드 - 기본 직렬화 형태에 적합한 클래스

public class Name implements Serializable {
    /**
     * 성. null이 아니어야 함.
     * @serial
     */
    private final String lastName;

    /**
     * 이름. null이 아니어야 함.
     * @serial
     */
    private final String firstName;

    /**
     * 중간이름. 중간이름이 없다면 null.
     * @serial
     */
    private final String middleName;
}

❌ 예제 코드 - 기본 직렬화에 부적절한 클래스

public final class StringList implements Serializable {
    private int size = 0;
    private Entry head = null;

    private static class Entry implements Serializable {
        String data;
        Entry next;
        Entry previous;
    }
}

✅ 개선된 커스텀 직렬화 코드

private void writeObject(ObjectOutputStream s) throws IOException {
    s.defaultWriteObject();
    s.writeInt(size);
    for (Entry e = head; e != null; e = e.next)
        s.writeObject(e.data);
}

private void readObject(ObjectInputStream s)
        throws IOException, ClassNotFoundException {
    s.defaultReadObject();
    int numElements = s.readInt();
    for (int i = 0; i < numElements; i++)
        add((String) s.readObject());
}

💡 새롭게 알게 된 점

  • transient 키워드는 단순히 직렬화 제외를 위한 도구가 아니라, 논리 상태와 무관한 필드를 구분하기 위한 의도적 신호다.

📚 정리

  • 기본 직렬화를 무조건 사용하지 말고, 논리적 표현과 물리적 표현의 일치 여부를 먼저 따져보자.
  • writeObject/readObject를 직접 구현해 커스텀 직렬화 형태를 설계하는 것이 장기적인 유지보수에 유리하다.
  • 직렬화는 한번 선택하면 바꾸기 어렵기 때문에, 직렬화 형태도 API 수준으로 진지하게 다뤄야 한다.
  • 실제 프로젝트에서는 설정 파일이나 캐시, 복잡한 객체 상태 저장 시, 커스텀 직렬화 형태를 도입해 버전 관리와 유연성을 확보할 수 있다.

📢 댓글로 각자의 학습 내용을 공유해주세요!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions