[Effective Java] readObject 메소드는 방어적으로 작성하라

들어가며

클래스를 직렬화하기로 결정했다면 readObject 메소드 또한 하나의 public 생성자 처럼 다뤄야한다. 그렇기 때문에 불변을 유지해야하는 클래스의 경우 readObject 메소드에 방어적 복사를 수행해야 한다. 즉, 객체를 역직렬화할 때는 클라이언트가 소유해서는 안되는 객체 참조를 갖는 필드를 모두 반드시 방어적 복사를 해야한다. 다음은 적시에 방어적 복사본을 만들라의 코드에 직렬화 메소드를 작성한 것이다.

1
2
3
4
5
6
7
8
9
10
11
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();

//방어적 복사를 유효성 검사 이전에 실행한다.
//유효성 검사 이후에 방어적 복사를 수행하면 그 찰나의 사이에 값이 변경될 수 있기 때문이다.
start = new Date(start.getTime());
end = new Date(end.getTime());

if (start.compareTo(end) > 0)
throw new InvalidObjectException(start + " is later then " + end);
}

다음은 안전한 readObject 메소드를 작성하는 지침이다.

  1. private이어야 하는 객체 참조 필드는 각 필드가 가리키는 객체를 방어적으로 복사하라. 불변 클래스 내의 가변 요소가 여기 속한다.
  2. 모든 불변식을 검사하여 어긋나는게 발견되면 InvalidObjectException을 던진다. 방어적 복사 다음에는 반드시 불변식 검사가 뒤따라야 한다.
  3. 역직렬화 후 객체 그래프 전체의 유효성을 검사해야 한다면 ObjectInputValidation 인터페이스를 사용하라.
  4. 직접적이든 간접적이든 재정의할 수 있는 메소드는 호출하지 말자.
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/25/Languages/Effective%20JAVA/item88/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.