본문 바로가기

프로그래밍/JAVA

직렬화를 할 때 유의해야 할 사항

자바에서는 직렬화를 통해서 객체를 손쉽게 저장하고 읽어올 수 있다.
하지만 이를 사용할 때에는 한가지 유의해야 할 점이 있다.

한 상황을 생각해보자.

자동차를 관리하는 프로그램을 만들었다고 하자.
이 프로그램은 자동차 객체를 생성하여 직렬화 한 다음에 이를 파일에 저장해서 자동차 목록을 관리한다.
사용자는 아무 불편없이 프로그램을 잘 사용하고 있었다. 그런데 어느날 유명한 자동차 회사에서 자동차에 하늘을 날 수 있는 기능을 추가했다. 그래서 내가 만든 자동차 관리 프로그램에서 자동차가 하늘을 날 수 있는지 없는지를 나타내는 속성이 필요해졌다.
그래서 한치의 망설임도 없이 자동차 클래스에 canFly라는 boolean형의 변수를 추가했다. 그리고 나서 고객에게 업데이트 된 프로그램을 재배포했다.
그런데 배포를 완료한 이후로 고객들에게 전화가 왔다.
프로그램이 제대로 동작하지 않는다는 것이었다.
어떻게 동작하지 않는지 물어보니 새로운 자동차를 등록하는 것은 잘 되는데, 기존 자동차의 목록을 가져오는 것이 안된다고 하는 것이었다.

도대체 문제가 무엇일까? 왜 잘되던 프로그램이 갑자기 제대로 동작하지 않는 것일까?
바로 직렬화 때문이다.
직렬화를 하게 되면 쉽게 객체를 저장할 수 있다는 장점이 있지만 반면에 그 클래스가 바뀔 경우 예외가 발생하는 단점이 있다.

왜냐하면 객체를 직렬화하게 되면 그 객체가 속한 클래스의 버전 ID가 생기게 되는데 이 버전 ID는 클래스의 구조에 따라 다른 값을 가지게 된다.
이 ID를 serialVersionUID라고 하고 static final long으로 할 것을 권하고 있다.
이클립스에서는 Serializable을 구현하게 되면 그 클래스 명에 노란색 밑줄이 생기게 되는데 마우스를 가져가보면 serialVersionUID를 생성하도록 되어있다.

아래의 그림은 Car클래스에 Serializable을 구현했는데 serialVersionUID를 만들지 않았을 경우 발생하는 노란 밑줄을 보여주고 있다.
사용자 삽입 이미지

위와 같은 상황에서 Car에 마우스를 가져가면 아래와 같은 그림이 나온다.
사용자 삽입 이미지
위의 그림에서 2번째 Add generated serial version ID를 클릭하게 되면 자동으로 클래스 구조에 맞게 변수 값을 할당하게 된다.

만약 Serializable을 구현한 클래스에서 serialVersionUID를 생성하지 않는다면 내부적으로 serialVersionUID를 가지고 있게 된다. 그래서 JVM에서 역직렬화를 할 때에 역직렬화하는 객체의 serialVersionUID와 이를 담을 객체의 serialVersionUID를 비교하게 되는데 이 둘의 값이 다르다면 예외를 발생시키게 된다.

그래서 이러한 문제를 해결하기 위해 serialVersionUID를 클래스 안에서 명시하여 특정 값으로 고정시키면 클래스가 바뀌더라도 예외를 발생시키지 않는 것이다. 하지만 이렇게 serialVersionUID의 값을 명시하게 되면 예외가 발생하지는 않지만 프로그래머가 클래스를 변경할 때에 문제가 생기지 않도록 세심한 주으를 기울여야 한다. 이 부분은 철저히 프로그래머가 책임을 져야 하는 부분이다.