ClassCastException - 왜 Optional 을 사용할 수 없을까?

시은·2024년 2월 18일
0
post-thumbnail

처음보는 Exception 🫣

로그인한 유저를 컨텍스트 홀더에서 꺼내서 건내려는데…

@Component
@RequiredArgsConstructor
public class AuthUtil {
    private final TokenUtil tokenUtil;

    public Long getLoginUserIndex() {
        Optional<User> user = getLoginUser();
        Long userId = user.get().getId();
        return userId;
    }

    public Optional<User> getLoginUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        return (Optional<User>) principal;
    }
		...

으잉?

호다닥 에러문구를 보니 아래와같은 에러가 저를 반겨주었습니다.

java.lang.ClassCastException: class com.example.budget.domain.user.User cannot be cast to class java.util.Optional (com.example.budget.domain.user.User is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @2d7e1886; java.util.Optional is in module java.base of loader 'bootstrap')
at com.example.budget.global.util.AuthUtil.getLoginUser(AuthUtil.java:25) ~[classes/:na]

대략 user 를 찾을때 Optional 인게 문제인것 같은데… 왜 그런걸까요? 🤔


Optional 로 Casting 될 수 없나요?

Optional 은 null 이 올 수 있는 값을 감싸는 Wrapper 클래스 입니다. 이를 통해 Null Pointer Exception 을 방지할 수 있습니다. 또한 각종 메서드를 제공하기도 하죠.

그럼 casting 은 뭘까요? casting 은 특정한 객체가 다른 유형의 instance 인 것처럼 처리되어야 함을 컴파일러에게 알리는 방법 입니다. 단, 이 프로세스는 실제로 cast 되는 객체가 대상 유형 혹은 하위 클래스의 instance 인 경우에만 작동합니다.

Opitonal 안에는 객체가 들어가니까 casting 될 수 있는거 아닌가? 라고 생각할 수도 있습니다. Optional의 T 또는 일반 유형은 모든 유형의 객체에 대한 자리 표시자 입니다. 객체 자체가 아니라 나중에 지정하게 될 유형을 나타내는 기호라는 점에서 우리가 일반적으로 생각하는 객체가 아닙니다.

즉, 객체는 구조와 목적이 근본적으로 다르기 때문에 Optional로 직접 처리할 수 없습니다. 객체는 무엇이든 될 수 있지만 Optional는 특히 T 유형 객체의 컨테이너 이기 때문이죠. (비유하자면 객체 와 T 는 사과, Optional 는 사과가 들어있는 박스라고 할 수 있습니다.)

그래서 아래와 같이 Optional 을 제외해주었고, 결과는 제대로 나왔습니다.

public Long getLoginUserIndex() {
    User user = getLoginUser();
    Long userId = user.getId();
    return userId;
}

public User getLoginUser() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    Object principal = authentication.getPrincipal();
    return (User) principal;
}
profile
창의력 대장이 되기 위한 여정

0개의 댓글