TIL - 3/6

헨도·2025년 3월 6일
0

TIL

목록 보기
14/21
post-thumbnail

직렬화(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 필수 값은 아니다.
    1. 호환 가능한 클래스는 SUID 값이 고정되어 있다.
    2. 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 를 직접 명시해도 예외가 발생하는 경우

멤버 변수 명은 같은데 타입이 바뀔 경우

  1. 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;
}
  1. 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;
    // phone 멤버 변수 제거
}

// 추가 시
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/

profile
Junior Backend Developer

0개의 댓글