
직렬화(Serializable) 란?
- JVM 메모리의 객체 데이터를 바이트 형태로 반환하는 기술
역직렬화(DeSerializable) 란?
- 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM 으로 상주시키는 기술
문제
public class Member implements Serializable {
private String name,
private String email,
private Integer age
}
- 위 코드를 직렬화 후 다시 역직렬화 시, 문제 발생 X
public class Member implements Serializable {
private String name,
private String email,
private Integer age
private String phone
}
- 이전에 직렬화한 데이터를 Member 객체 컬럼 추가 후 역직렬화 시, 에러가 발생
java.io.InvalidClassException: woowahan.blog.exam1.Member;
local class incompatible:
stream classdesc serialVersionUID = -8896802588094338594,
local class serialVersionUID = 7127171927132876450
- 즉, SerialVersionUID(SUID) 정보가 일치하지 않기에 발생하는 오류
결론
- 직렬화 할 때 SUID 는 특정 클래스 버전과 구조로 만들어지기 때문에 SUID와 변경된 class path 나 멤버변수의 ID 가 일치하지 않아서 나는 오류이다.
Q. 우리는 SUID 를 선언해주지 않았는데?
- A. 자바 직렬화 문서에 따르면...
1. SUID 필수 값은 아니다.
- 호환 가능한 클래스는 SUID 값이 고정되어 있다.
- SUID 값이 선언되지 않으면 클래스 기본 해시 값을 사용한다.
-> 이 스펙으로 인해 자동 추가된 UID
그럼 SUID 를 추가한 형태는?
public class Member implements Serializalbe {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String phone;
}
- 위 코드처럼 SUID를 직접 명시하여 관리할 수 있다.
SUID 를 직접 명시해도 예외가 발생하는 경우
멤버 변수 명은 같은데 타입이 바뀔 경우
- Integer → Long 변경 시
public class Member implements Serializalbe {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String phone;
private Integer age;
}
public class Member implements Serializalbe {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String phone;
private Long age;
}
- String → StringBuilder 변경 시
public class Member implements Serializalbe {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String phone;
}
public class Member implements Serializalbe {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private StringBuilder phone;
}
의외로 오류가 나지 않는 경우
- 너무 엄격해서 멤버 변수를 추가하거나 삭제할 때도 오류가 날 것 같았는데 안난다
public class Member implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String email;
}
public class Member implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String address;
}
해결방안
클래스 구조 변경 시 버전 관리:
- 클래스의 구조가 변경될 때
serialVersionUID
를 명시적으로 정의하고,
클래스를 변경할 때는 이전 버전과의 호환성을 고려
클래스 이름 및 패키지 변경 시 주의
- 클래스 이름이나 패키지를 변경할 때는 역직렬화 과정에서 문제가 발생할 수 있으므로,
이전 버전에서 사용하는 클래스들을 함께 관리하거나 이름 변경 시 호환성을 유지
참조
https://techblog.woowahan.com/2551/