개발서적/Effective Java

    [Effective Java] 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라

    Serializable의 보안 이슈 Serializable을 구현하기로 결정한 순간 언어의 정상 메커니즘인 생성자 이외의 방법으로 인스턴스를 생성할 수 있게 된다. 따라서 버그와 보안 문제가 일어날 가능성이 커진다는 문제가 있다. 이를 해결하기 위해 직렬화 프록시 패턴을 사용할 수 있다. 직렬화 프록시 패턴 직렬화 프록시 패턴을 구현하는 방법은 다음과 같다. 바깥 클래스의 논리적 상태를 정밀하게 표현하는 중첩 클래스를 설계해 private static으로 선언한다. 이 중첩 클래스가 바로 바깥 클래스의 직렬화 프록시이다. 중첩 클래스의 생성자는 단 하나여야 하며, 바깥 클래스를 매개변수로 받아야 한다. 이 생성자는 단순히 인수로 넘어온 인스턴스의 데이터를 복사한다. private static class ..

    [Effective Java] 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라

    다음은 아이템 3에서 소개한 싱글톤 패턴을 구현하는 방법 중 한 가지이다. public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTheBuild() { ... } } 이 클래스에서 implement Serializable을 추가하는 순간 더 이상 싱글턴이 아니게 된다. 어떤 readObject를 제공하더라도 이 클래스가 초기화될 때 만들어진 인스턴스와는 별개인 인스턴스를 반환하게 된다. readResolve 역직렬화 readResolve 기능을 이용하면 readObject가 만들어낸 인스턴스를 다른 것으로 대체할 수 있다. 역직렬화한 객체의 클래스가 readR..

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

    readObject는 또 다른 생성자이다 readObject 메서드는 또 다른 public 생성자이다. 보통의 생성자처럼 readObject 메서드에서도 인수가 유효한지 검사해야 하고 필요하다면 매개변수를 방어적으로 복사해야 한다. readObject가 이 작업을 제대로 수행하지 못하면 공격자는 아주 손쉽게 해당 클래스의 불변식을 깨뜨릴 수 있다. 객체의 유효성 검사 readObject 메서드가 defaultReadObject를 호출한 다음 역직렬화된 객체가 유효한지 검사하자. 이 유효성 검사에 실패하면 InvalidObjectException을 던지게 하여 잘못된 역직렬화가 일어나는 것을 막을 수 있다. private void readObject(ObjectInputStream s) throw IOEx..

    [Effective Java] 커스텀 직렬화 형태를 고려해보라

    기본 직렬화 형태는 주의해서 사용하자 클래스가 Serializable을 구현하고 기본 직렬화 형태를 사용한다면 다음 릴리스 때 제한이 생겨버린다. 기본 직렬화 형태는 유연성, 성능, 정확성 측면에서 신중히 고민한 후 합당할 때만 사용해야 한다. 기본 직렬화 형태 객체가 포함한 데이터들과 그 객체에서부터 시작해 접근할 수 있는 모든 객체를 담아낸다. 이상적인 직렬화 형태는 물리적인 모습과 독립된 논리적인 모습만 표현해야 한다.ㅍ 만약 객체의 물리적 표현과 논리적 내용이 같다면 기본 직렬화 형태라도 무방하다. e.g ) 성명은 논리적으로 이름, 성, 중간이름이라는 3개의 문자열로 구성되며, 다음 코드의 인스턴스 필드들은 이 논리적 구성요소를 정확히 반영한다. import java.io.Serializable..

    [Effective Java] Serializable을 구현할지는 신중히 결정하라

    어떤 클래스의 인스턴스를 직려화할 수 있게 하려면 클래스 선언에 implements Serializable만 붙이면 된다. 직렬화를 하기는 정말 쉽지만, 길게 보면 아주 값비싼 일이다. Seriazliable의 다양한 문제 릴리스한 뒤에는 수정이 어렵다 클래스가 Serializable을 구현하면 직렬화된 바이트 스트림 인코딩(직렬화 형태)도 하나의 공개 API가 된다. 테스트할 것이 늘어난다. 모든 직렬화 된 클래스에는 고유 식별 번호를 부여 받는데, 이 번호는 클래스의 모든 정보를 고려한 해싱 방법으로 생성된다. (글자 하나만 달라져도 해시값이 달라진다) 버그와 보안에 위험이 생긴다 객체는 생성자를 만드는 게 기본이다. 하지만 역직렬화는 일반 생성자의 문제가 그대로 적용되는 '숨은 생성자'이다. 불변식..