자바 프로젝트에서 예외처리를 위해 Exception 클래스를 정의하다보면 "'XXX' does note define a 'serialVersionUID'"라는 경고 문구를 만나게 될 때가 있다. 다음 Exception 클래스를 작성하면 개발환경 설정에 따라서 경고 메시지를 보게 된다.
public class TestException extends IOException {
public TestException(String message) {
super(message);
}
}
경고 문구를 해석하자면 'serialVersionUID'를 정의하지 않았다는 의미다. 'serialVersionUID'가 뭐길래 경고 메시지를 띄우는 것일까?
serialVersionUID
serialiVersionUID를 정의하지 않았다고 해서 코드가 동작하지 않는 등의 문제는 발생하지 않는다. 다만 클래스를 직렬화(Serialize)하는 경우 문제가 발생할 수 있다.
serialVersionUID는 자바의 직렬화(Serialize)와 역직렬화(De-serialize) 과정에서 관여하는 값이다. 자바 클래스를 역직렬화 할 때, 직렬화된 데이터에 저장되어 있는 serialVersionUID와 역직렬화 할 클래스의 serialVersionUID를 비교하여 같은 경우에만 정상 동작한다. 만약 이 값이 다르면 'java.io.InvalidClassException'이 발생하게 된다.
기본적으로는 직렬화된 클래스와 동일한 클래스로 역직렬화를 하지만 호환되는 클래스의 경우 역직렬화를 허용하고 싶을 경우가 있다. 예를 들어 다음 클래스를 직렬화했다고 하자.
public class Employee implements Serializable {
private String name;
private String dept;
private int age;
}
직렬화된 데이터를 다음 클래스로 역직렬화 한다고 해보자.
public class Employee implements Serializable {
private String name;
private String dept;
private int age;
// 추가 멤버
private String phoneNumber;
}
앞쪽의 멤버들은 동일한데 뒤쪽에 옵셔널(Optional)한 멤버들이 추가된 경우, 앞쪽의 멤버들만 역직렬화해서 채워넣으면 될 것 같지 않은가?
자바 실행환경에서 Serializable 클래스에 serializeVerionUID를 지정하지 않으면 JVM에서 클래스에 버전 번호를 부여하게 된다. 만약 클래스의 구조가 다르면 이 serialVersionUID 값도 달라지게 되고, 호환이 가능한 클래스이지만 역직렬화를 할 수 없게 된다.
이 보다 더 큰 문제는 명시적으로 serialVersionUID를 선언하지 않은 경우 JVM이 런타임에 기본 값을 생성하게 되는데, 만약 직렬화된 객체를 다른 머신의 JVM으로 보내서 역직렬화하는 경우 JVM이 동일한 클래스에 대해서 serialVersionUID를 다르게 계산하는 경우가 있을 수 있다. 이 경우 논리적으로 동일한 클래스 정의임에도 직렬화된 객체를 역직렬화 할 수 없는 경우가 발생할 수 있다.
따라서 애초에 명시적으로 특정 값을 선언해주는게 안전하다.
IntelliJ에서 'serialVersionUID' Warning 체크 켜기
기본적으로 IntelliJ에서는 serialVersionUID를 정의하지 않았다고 해서 Warning을 띄우지 않는다. 하지만 위에서 말했듯이 다른 JVM, 다른 머신으로 직렬화하여 전송할 때 문제가 생길 수 있다. 따라서 명시적으로 개발환경에서 이런 Warning을 체크해주면 좋다.
IntelliJ에서 serialVersionUID Warning을 체크하기 위해서 다음 설정을 켜주면 된다.
[Preferences] -> [Editor] -> [Code Style] -> [Inspections] -> [Serialization issues] -> "Serializable class without 'serialVersionUID"를 체크하면 된다.
Warning 해결 방법 1 - serialVersionUID 자동추가
경고 메시지가 뜨는 클래스의 이름 부분에서 인텔리J의 'intention actions' 기능을 이용하면 쉽게 serialVersionUID를 추가할 수 있다. 경고 메시지가 뜨는 부분 (하이라이트 된 부분)에서 Mac의 경우 ⌥⏎ (option + enter) 버튼을 누르면 위 그림처럼 옵션을 선택할 수 있다. 'Add 'serialVersionUID field'를 선택하면 자동으로 추가된다. (그 밖에는 [Alt] + enter 버튼을 누르면 된다.)
Warning 해결 방법 2 - IntelliJ Plugin 사용
[Preference] -> [Plugins] -> [Browse repositories] 버튼을 클릭한다. 그리고 "GenerateSerialVersionUID"를 검색해서 설치한다. 그리고 인텔리J를 다시 시작하면 해당 기능을 사용할 수 있다.
[Code] -> [Generate] 메뉴를 선택하면 위 그림처럼 SerialVersionUID 를 만들 수 있다.
이런식으로 serialVersionUID 멤버가 생성된다.
Warning 해결방법 3 - 애너테이션으로 무시하기
Exception 같은 클래스는 직렬화에 사용하지 않음을 보장 할 수 있는 경우가 있다. 이럴 때에는 그냥 해당 경고를 무시할 수도 있다.
@SuppressWarnings("serial")
위 애너테이션(Annotation)을 클래스 이름 위에 선언해놓으면 경고 메시지를 띄우지 않는다.
Reference
https://stackoverflow.com/questions/12912287/intellij-idea-generating-serialversionuid
댓글