🔍 직렬화란?
객체의 내용을 바이트 단위로 변환하여 파일 또는 네트워크를 통해 송수신 가능하게끔 하는 것을 의미한다. 예를 들어, 우리가 사용하는 IDE를 종료하고 새로 키더라도 편집하던 화면과 위치를 그대로 보존하고 있는데, 이것은 우리의 사용정보를 '직렬화'해 PC 어딘가에 저장해놓고 있다가 사용자가 IDE를 실행한 시점에 사용정보를 불러오기 때문이다. 사용자의 브라우저와 서버 간의 데이터를 통신할 때 자주 사용하는 JSON도 직렬화의 한 형태인 것이다.
자바는 자바 객체를 직렬화 하는 기능을 보유하고 있다. 직렬화된 파일이나 데이터는 다른 자바 기반의 시스템에서 불러와 그대로 객체로 활용할 수 있는 큰 이점이 있다.
🔍 코드로 알아보기
import java.io.Serializable;
public class CodingQuiz implements Serializable {
private String id;
private int level;
private String quizName;
private transient String myHiddenName; // transient가 선언된 속성은 직렬화 대상에서 제외된다.
...
@Override
public String toString() {
return String.format(
"CodingQuiz [id='%s', level='%d', quizName='%s', myHiddenName='%s']",
id, level, quizName, myHiddenName);
}
}
자바 객체로 직렬화하기 위해 _!Serializable!_ 인터페이스를 구현한다. _!Serializable!_는 아무것도 정의되지 않은 인터페이스이지만, 직렬화 할 수 있다는 선언적 의미를 지닌다.
_!myHiddenName!_ 속성은 _!transient!_가 선언되어 있는데, 이는 직렬화 대상에서 제외된다. 사용자의 비밀번호나 개인정보 등을 포함해 직렬화 해버릴 경우 그대로 외부로 노출되기 때문에 이런 상황을 방지하기 위해 사용한다.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
class Main {
public static void main(String[] args) {
try {
CodingQuiz codingQuiz = new CodingQuiz();
codingQuiz.setId("1");
codingQuiz.setQuizName("MyQuiz12");
codingQuiz.setLevel(3);
codingQuiz.setMyHiddenName("보여져서는 안되는 값");
FileOutputStream fos = new FileOutputStream("SerializedMyQuiz.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(codingQuiz);
oos.close();
FileInputStream fis = new FileInputStream("SerializedMyQuiz.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
CodingQuiz cq = (CodingQuiz) ois.readObject();
ois.close();
System.out.println(cq);
} catch (Exception e) {
e.printStackTrace();
}
}
}
_!ObjectOutputStream!_, _!ObjectInputStream!_을 통해 자바 직렬화를 구현할 수 있다. 직렬화된 자바 객체는 역직렬화를 통해 다시 자바 객체 그대로 사용할 수 있다. 다른 직렬화 방식이었다면 역직렬화한 데이터로 인스턴스를 새로 생성 했었을 것이다.
🔍 주의사항
import java.io.Serializable;
public class CodingQuiz implements Serializable {
private static final long serialVersionUID = 1L; // 직접 정의해주자
private String id;
private int level;
private String quizName;
private transient String myHiddenName;
...
✅ 직렬화 대상인 클래스의 변수나 메서드가 변경되어, _!serialVersionUID!_가 변경되면, 역직렬화 할 수 없게 된다. 관련 데이터를 모두 버리게 되는 것이다. _!serialVersionUID!_를 직접 클래스 내에 정의하고 관리하는 방법이 권장된다.
🔍 정리하며
자바 직렬화를 수행하게 되는 경우 보안 상의 공격범위가 매우 넓어지게 된다. 직렬화된 바이트 데이터에 대한 직접적인 접근이나 예기치 못한 악의적 의도가 담긴 직렬화된 데이터를 역직렬화 할 수도 있는 것이다. 대부분의 경우 CSV나 JSON과 같은 직렬화 방식을 채택해 개발하겠지만, 자바 직렬화가 필요한 경우에는 반드시 그 위험성을 인지해야한다.
✔️ 소스코드 및 온라인 실행환경 https://replit.com/@peaks26/Serializable?v=1