Skip to content

[아이템 90] 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라 #92

@zziri

Description

@zziri

Serializable 구현 문제

  • Serializable을 구현하면 생성자 이외의 방법으로 인스턴스 생성 가능
  • 버그와 보안문제
    -> 직렬화 프록시 패턴

SerializableProxy 구현

public class Period implements Serializable {
    private final Date start;
    private final Date end;
    
    public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        
        if(this.start.compareTo(this.end) > 0) {
            throw new IllegalArgumentException(start + "가 " + end + "보다 늦다.");
        }
    }
    private static class SerializationProxy implements Serializable {
        private final Date start;
        private final Date end;

        public SerializationProxy(Period p) {
            this.start = p.start;
            this.end = p.end;
        }
    }
}

직렬화 프록시는 바깥 클래스와 완전히 같은 필드로 구성

Period.writeReplace

public class Period implements Serializable {
    private Object writeReplace() {
        return new SerializationProxy(this);
    }
}

직렬화시 호출
바깥 클래스(Period) 타입을 직렬화할 수 없음

Period.readObject

public class Period implements Serializable {
    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
        throw new InvalidObjectException("프록시가 필요합니다.");
    }
}

역직렬화시 호출
Period를 직접 역직렬화할 수 없음

Period.SerializableProxy.readResolve

public class Period implements Serializable {
    private static class SerializationProxy implements Serializable {
        private Object readResolve() {
            return new Period(start, end);
        }
    }
}

직렬화 프록시를 통해서만 역직렬화 가능
생성자 혹은 정적 메서드를 통해서만 객체를 생성하므로 불변식이 깨질 위험이 낮음

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions