[TIL 14일차] Sprint Mission2.2 - 디스코드: File IO를 통한 데이터 영속화와 레포지토리 설계 및 구현
오늘의 성취
- 개발 진행 상황
- File IO를 통한 데이터 영속화
- JCF가 아닌 FileIO와 객체 직렬화를 통해 파일에 데이터 저장/삭제를 구현
- 레포지토리 설계 및 구현
- 저장 로직과 관련된 기능을 도메인 모델 별 인터페이스, 구현체 구현
- File IO를 통한 데이터 영속화
- Unchecked warning?
- 자바 제네릭 관련하여 컴파일러가 “타입 안전을 100% 보장 못 하겠다”라고 경고하는 것
- 원인
- 타입 소거 발생 : 자바 제네릭은 컴파일할 때만 타입 체크를 하고, 런타임(실행)할 때는
<>안의 정보가 대부분 사라지는 현상 - 원인 예시 :
Map<UUID, User> m = new HashMap<>();- 컴파일러는
m.put(UUID, User);만 허용하고,m.put("hello", 123);같은 건 컴파일 에러로 막음 - 런타임 중에는 m은 UUID와 User라는 정보가 없는 Map으로만 보임
- 컴파일러는
- 타입 소거 발생 : 자바 제네릭은 컴파일할 때만 타입 체크를 하고, 런타임(실행)할 때는
- 발생 예시
unchecked cast: List<String> x = (List<String>) obj;ObjectInputStream.readObject()처럼 Object로 읽어온 걸 제네릭 타입으로 캐스팅할 때
Object obj = ois.readObject(); List<String> list = (List<String>) obj; // unchecked cast 경고- 즉, 제네릭은 런타임에 타입 정보가 지워지기 때문에 런타임에 진짜
List<String>인지 확실히 검증할 방법이 없어서, 컴파일러가 경고를 띄우는 것
WriteAbortedException- 직렬화 도중
NotSerializableException이 발생해서 저장이 중단(abort)되었다는 랩핑된 예외 - 파일에 제대로 저장이 안되었거나 깨졌을 가능성이 매우 높음
Serializable미구현으로 인한 예외로,Serializable을 구현하면 정상 동작됨.
- 직렬화 도중
- 파일에서 데이터를 읽어올 때마다 UUID가 달라지는 문제 발생
- 자바 직렬화 규칙상 서브클래스(User)가 Serializable이어도 부모(BaseEntity)가 Serializable이 아니면 역직렬화할 때 부모 생성자가 실행됨
- 즉, 파일이 존재하고, 데이터 로드가 성공해도 UUID가 바뀌는 문제가 발생
- 해결 방법
- BaseEntity 자체를 직렬화 가능하게 Serializable 구현하기
프로젝트 요구사항
1. 기본 요구사항
1-1. File IO를 통한 데이터 영속화
- 다음의 조건을 만족하는 서비스 인터페이스의 구현체를 작성하세요.
- 클래스 패키지명:
com.sprint.mission.discodeit.service.file - 클래스 네이밍 규칙:
File[인터페이스 이름] - JCF 대신 FileIO와 객체 직렬화를 활용해 메소드를 구현하세요.
- 객체 직렬화/역직렬화 가이드
- 클래스 패키지명:
Application에서 서비스 구현체를File*Service로 바꾸어 테스트해보세요.
1-2. 서비스 구현체 분석
JCF*Service구현체와File*Service구현체를 비교하여 공통점과 차이점을 발견해보세요.- “비즈니스 로직”과 관련된 코드를 식별해보세요.
- “저장 로직”과 관련된 코드를 식별해보세요.
1-3. 레포지토리 설계 및 구현
참고: 레포지토리는 데이터를 관리하는 로직을 가짐
- “저장 로직”과 관련된 기능을 도메인 모델 별 인터페이스로 선언하세요.
- 인터페이스 패키지명:
com.sprint.mission.discodeit.repository - 인터페이스 네이밍 규칙:
[도메인 모델 이름]Repository
- 인터페이스 패키지명:
- 다음의 조건을 만족하는 레포지토리 인터페이스의 구현체를 작성하세요.
- 클래스 패키지명:
com.sprint.mission.discodeit.repository.jcf - 클래스 네이밍 규칙:
JCF[인터페이스 이름] - 기존에 구현한
JCF*Service구현체의 “저장 로직”과 관련된 코드를 참고하여 구현하세요.
- 클래스 패키지명:
- 다음의 조건을 만족하는 레포지토리 인터페이스의 구현체를 작성하세요.
- 클래스 패키지명:
com.sprint.mission.discodeit.repository.file - 클래스 네이밍 규칙:
File[인터페이스 이름] - 기존에 구현한
File*Service구현체의 “저장 로직”과 관련된 코드를 참고하여 구현하세요.
- 클래스 패키지명:
//...
GitHub Repository 주소
https://github.com/JungH200000/10-sprint-mission/tree/sprint2
Leave a comment