Serializable 인터페이스를 구현하겠다는 결정을 내리게 되면 버그나 보안 결함이 생길 가능성이 높다. 하지만 이런 위험을 크게 줄일 수 있는 기술이 하나 있다. 직렬화 프락시 패턴이라고 알려진 기법이다.


 우선 바깥 클래스 객체의 논리적 상태를 간결하게 표현하는 직렬화 가능 클래스를 private static 중첩 클래스로 설계한다. 이 중첩클래스를 직렬화 프락시라고 부르는데, 바깥 클래스를 인자 자료형으로 사용하는 생성자를 하나만 가진다. 이 생성자는 인자에서 데이터를 복사하기만 한다. 일관성 검사를 할 필요도 없고, 방어적 복사를 할 필요도 없다.


 아래는 Period 클래스의 프락시 코드이다.


 이 프락시를 추가한 다음, 바깥 클래스에 아래의 writeReplace 메서드를 구현한다.

이 메서드가 있으면 직렬화 시스템은 바깥 클래스 객체 대신 SerializationProxy 객체를 직렬화한ㄷ. 다시 말해서, writeReplace 메서드는 직렬화가 이루어지기 전에 바깥 클래스 객체를 직렬화 프락시 객체로 변환한다.


writeReplace 메서드를 갖추게 되면 직렬화 시스템은 바깥 클래스로 직렬화된 객체는 절대로 만들지 않는다. 하지만 공격자는 클르새의 불변식을 훼손하고자 그런 객체를 만들려 할 수도 있다. 그런 공격을 막으려면 아래의 readObject 메서드를 바깥 클래스에 추가해주면 된다.



마지막으로, SerializationProxy 클래스에 자기와 논리적으로 동일한 바깥 클래스 객체를 반환하는 readResolve 메서드를 추가해야 한다. 이 메서드가 있으면 직렬화 시스템은 역직렬화를 끝내자마자 직렬화 프락시 객체를 다시 바깥 클래스 객체로 변환하게 된다.


요약

클라이언트가 확장할 수 없는 클래스에 readObject나 writeObject를 구현해야 할 때는 직렬화 프락시 패턴 도입을 고려해 보라는 것이다. 이 패턴은 단순하지 않은 불변식을 만족해야 하는 객체를 안정적으로 직렬화 하는 가장 쉬운 방법이다.



+ Recent posts