직렬화의 근본적인 문제는 공격범위가 너무 넓고 지속적으로 더 넓어져 방어하기 어렵다는 점이다.
직렬화 위험을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는것이다.
특히 신뢰할 수 없는 데이터는 절대로 역직렬화를 하지 말아야 한다.
Serializable을 구현하면 릴리스 한 뒤에는 수정하기 어렵다.
버그와 보안 구멍이 생길 위험성이 높아 진다. (아이템 85)
해당 클래스의 신버전을 릴리스 핳때 테스트 할 것이 늘어난다는 점이다.
Serializable 구현 여부는 가볍게 결정할 사안이 아니다 (단. 객체를 전송하거나 저장할때 자바 직렬화를 이용하는 프레임워크용으로 만든 클라스라면 선택의 여지가 없다.)
상속용으로 설계된 클래스 (아이템 19)는 대부분 Serializable을 구현하면 안되며, 이넡페이스도 대부분 Serializable을 확장해선 안된다.
내부 클래스 (아아템 24)는 직렬화를 구현하면 안된다.
먼저 고민해보고 괜찮다고 판단될 떄만 기본 직렬화 형태를 사용하라.
객체의 물리적 표현과 논리적 내용이 같다면 기본 직렬화 형태라도 무방하다.
기본 직렬화 형태가 적합하다고 결정 했ㄷ더라도 불변식 보장과 보안을 위해 readObject 메소드를 제공해야 할 때가 많다.
객체의 물리적 표현과 논리적 표현의 차이가 클때 기본 직렬화 형태를 사용하면 크게 네 가지 면에서 문제가 생긴다.
공개 API가 현재의 내부 표현 방식에 영구적으로 묶인다.
너무나 많은 공간을 차지 할수 있다.
시간이 너무 많이 걸릴수 있다.
스택 오버플로우를 일으킬수 있다.
해당 객체가 논리적 상태와 무관한 필드라고 확신할 때만 transient 한정자를 생략해야 한다.
객체의 전체 상태를 읽는 메소드에 적용해야 하는 동기화 메커니즘을 직렬화에도 적용해야 한다.
어떤 직렬화 형태를 택하든 직려로하 가능 클래스 모두에 직렬버전 UID를 명시적으로 사용하자.
구버전으로 직렬화된 인스턴스들과의 호환성을 끊을려는 경우를 제외하고 직렬버전 UID를 절대 수정하지 말아야 한다.
readObjet 메소드를 작성할 떄에는 언제나 public 생성자를 작성하는 자세로 임해야 한다.
readObject는 어떤 바이트 스트림이 넘어와더라도 유효한 인스턴스를 만들어 내야 한다.
private이어야 하는 객체 참조 필드는 각 필드가 가리키는 객체를 방어적으로 복사해라. 불변 클래스 내의 가변 요소가 여기 속한다.
모든 불변식을 검사하여 어긋나는 게 발견되면 InvalidObjectException을 던진다. 방어적 복사 다음에는 반드시 불변식 검사가 뒤따라야 한다.
역직렬화 후 객체 그래프 전체의 유효성을 검사해야한다면 ObjectInputValidation 인터페이스를 사용하라
직접적이던 간접적이던, 재정의 할수 있는 메소드는 호출 하지 말자
불변식을 지키기 위해 인스턴스를 통제해야 한다면 가능한 한 열거 타입을 사용하는 것이 좋다.
여의치 않는 상황에서 직렬화와 인스턴스 통제가 모두 필요하다면 readResolve메소드를 넣어야 하고 그 클래스에서 모든 참조타입 인스턴스 필드를 transient으로 선언해야 한다.