강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

woddnjs님의 프로필 이미지
woddnjs

작성한 질문수

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

31강 UserServiceV2 오류

작성

·

57

·

수정됨

0

31강에서 BookService 클래스에 강의와 똑같이 코드를 작성하였는데 실행하면 UserServiceV2 오류가 발생합니다.

UserRepository의 Optional<User> 형식을 받지 못해서 생기는 오류인 것 같은데, 어떻게 수정해야 하나요?

error: incompatible types: Optional<User> cannot be converted to User

User user = userRepository.findByName(name);

^

  • UserServiceV2.java

     

@Transactional
public void deleteUser(String name) {
    //SELECT * FROM user WHERE name = ?
    User user = userRepository.findByName(name);
    if (user == null) {
        throw new IllegalArgumentException();
    }
    userRepository.delete(user);
}
@Transactional
public void loanBook(BookLoanRequest request){
    //1. 책 정보 가져오기
    Book book = bookRepository.findByName(request.getBookName()).orElseThrow(IllegalArgumentException::new);

    //2. 대출 기록 정보 확인하여 대출 중인지 확인
    //3. 대출 중이면 예외 발생
    if(userLoanHistoryRepository.existsByBookNameAndIsReturn(book.getName(), false)){
        throw new IllegalArgumentException("진작 대출되어 있는 책입니다.");
    }

    //4. 유저 정보 가져오기
    User user = userRepository.findByName(request.getUserName())
            .orElseThrow(IllegalArgumentException::new);

    //5. 유저 정보와 책 정보 기반 UserLoanHistory 저장
    userLoanHistoryRepository.save(new UserLoanHistory(user.getId(), book.getName()));
}
  • UserRepository.java

    package com.group.libraryapp.domain.user;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import java.util.Optional;
    
    public interface UserRepository extends JpaRepository<User, Long> {
        Optional<User> findByName(String name);
    }

    우선 오류를 없애기 위해 UserRepository에서 Optional을 빼고 null처리를 하도록 수정하였는데, 실행 시 오류는 없지만 웹UI로 테스트하면 서버 내부 오류가 발생했다고 뜹니다. 어떻게 수정해야 제대로 처리되는지 모르겠습니다.

     

추가로 이렇게 수정하였을 때, 이후 코드를 작성할 때 Optional 형식이 아니어서 발생하는 다른 오류가 없는지도 궁금합니다.

package com.group.libraryapp.domain.user;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);
}
@Transactional
public void loanBook(BookLoanRequest request){
    //1. 책 정보 가져오기
    Book book = bookRepository.findByName(request.getBookName()).orElseThrow(IllegalArgumentException::new);

    //2. 대출 기록 정보 확인하여 대출 중인지 확인
    //3. 대출 중이면 예외 발생
    if(userLoanHistoryRepository.existsByBookNameAndIsReturn(book.getName(), false)){
        throw new IllegalArgumentException("진작 대출되어 있는 책입니다.");
    }

    //4. 유저 정보 가져오기
    User user = userRepository.findByName(request.getUserName());
    if(user == null){
        throw new IllegalArgumentException();
    }

    //5. 유저 정보와 책 정보 기반 UserLoanHistory 저장
    userLoanHistoryRepository.save(new UserLoanHistory(user.getId(), book.getName()));
}
  • UserServiceV2.java

     

    @Transactional
    public void deleteUser(String name) {
        //SELECT * FROM user WHERE name = ?
        User user = userRepository.findByName(name);
        if (user == null) {
            throw new IllegalArgumentException();
        }
        userRepository.delete(user);
    }

     

답변 1

0

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요! 🙂 질문 주셔서 감사합니다.

하나씩 말씀드려 보면.. 먼저

UserRepository의 Optional<User> 형식을 받지 못해서 생기는 오류인 것 같은데, 어떻게 수정해야 하나요?

는 추측해주신 내용이 맞습니다.

User user = userRepository.findByName(name);

라는 코드가 있을 때 findByName()Optional<User> 를 반환한다면, User 타입이 아닌 Optional<User> 로 받아야 합니다.

혹은 아예 findByName()이 User 를 반환하게 하고, 서비스 단에서 null check를 해줘도 괜찮고요!

추가로 이렇게 수정하였을 때, 이후 코드를 작성할 때 Optional 형식이 아니어서 발생하는 다른 오류가 없는지도 궁금합니다.

Optional은 객체 타입만 봤을 때 이 타입이 nullable (null이 들어갈 수 있는지) 한지, non-nullable 한지 알기 어렵다 보니 탄생한 객체로, Optional 로 감싸진 Optioan<T> 는 null이 들어갈 수 있다는 것을 보여줄 뿐, Optional 을 사용하지 않는다고 해서 추후 다른 오류가 생기지는 않습니다.

 

또한

실행 시 오류는 없지만 웹UI로 테스트하면 서버 내부 오류가 발생했다고 뜹니다. 어떻게 수정해야 제대로 처리되는지 모르겠습니다.

같은 경우는 웹 UI로 API를 호출 했을 때 '어떤 서버 내부 오류'가 발생한 건지 에러 로그를 보면 조금 더 자세히 말씀드릴 수 있을 것 같습니다. 🙂

 

자세한 상황과 함께 질문 남겨주셔서 감사드리고, 오류 로그는 올려주시면 한 번도 봐보겠습니다!

woddnjs님의 BE 개발 공부를 응원합니다. 🔥 감사합니다!

woddnjs님의 프로필 이미지
woddnjs
질문자

감사합니다!
UserServiceV2를

@Transactional
public void deleteUser(String name) {
    //SELECT * FROM user WHERE name = ?
    Optional<User> user = userRepository.findByName(name);
    if (user == null) {
        throw new IllegalArgumentException();
    }
    userRepository.delete(user);
}

이렇게 변경하였더니 delete에서 user를 사용하지 못하는 오류가 뜨는데,

그 다음 강의(34강)에 아래와 같은 코드가 나와서 그 코드대로 작성하였더니 오류 없이 실행이 가능한데, 이렇게 사용해도 되는 걸까요?

@Transactional
    public void deleteUser(String name) {
        //SELECT * FROM user WHERE name = ?
        User user = userRepository.findByName(name)
                .orElseThrow(IllegalArgumentException::new);
        userRepository.delete(user);
    }
최태현님의 프로필 이미지
최태현
지식공유자

네네 아래 코드와 같이 사용하셔도 괜찮습니다.

그래도 왜 아래 코드는 되고 위의 코드는 에러가 발생하는지 그 원리를 아시면 좋을 것 같은데요! 그 이유는 Optional<User>User는 다른 타입이기 때문에 그렇습니다.

예를 들어 아래 함수를 생각해보죠

public void printList(List<Integer> numbers) {
  for (int num : numbers) {
    // num 출력
  }
}

이 함수에

printList(Set.of(1, 2, 3));

이라는 코드를 사용할 수 있을까요? 없을까요?

 

정답은, 에러가 발생합니다. 왜냐하면 Set<Integer>List<Integer>다른 타입이기 때문이죠. 마찬가지로 xxxRepository.delete(?) 는 Entity인 User 같은 타입이 들어와야 하는데 Optional<User>User 와 다른 타입 이기 때문에 에러가 발생하게 됩니다.

 

또 진행하시면서 어려운 점 있으시면 편하게 질문 남겨주세요~ 감사합니다! 🙇

woddnjs님의 프로필 이미지
woddnjs

작성한 질문수

질문하기