New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[kwj1270-issue51] Exception 관련 리팩토링 #53
Conversation
Codecov Report
@@ Coverage Diff @@
## kwj1270 #53 +/- ##
=============================================
+ Coverage 96.66% 97.96% +1.30%
- Complexity 120 188 +68
=============================================
Files 30 52 +22
Lines 300 492 +192
Branches 5 5
=============================================
+ Hits 290 482 +192
Partials 10 10
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상당히 많은 file change 😢 최대한 다 읽어보았습니다!
항상 우지님의 코드는 꼼꼼해서 보기 좋은것같아요 ㅎㅎ
개인적으로 코드 읽으면서 나라면 어떨까 싶은 부분에 대해서 코멘트 남겨두었으니 의견으로만 봐주세요 ㅎㅎ :)
@@ -28,7 +29,7 @@ public User login(final Email email, final Password password) { | |||
|
|||
private User findByEmail(final Email email) { | |||
return userRepository.findByEmail(email) | |||
.orElseThrow(IllegalArgumentException::new); | |||
.orElseThrow(() -> new EmailNotFoundException(email.email())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
람다식으로 다시 변경하게 된 이유가 있을까용?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
커스텀 Exception 만들면서 매개변수로 email String 값을 받도록 해서 불가피하게 바꾸게 되었어요!
내부 String만 사용하면 메서드 참조 가능하지만, 매개변수 때문에 추가했습니다.
@@ -14,13 +14,13 @@ | |||
import javax.validation.Valid; | |||
|
|||
@RestController | |||
public class AuthRestController { | |||
public class AuthApi { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
물론 취향차이일 수도 있고, 해당 Api 클래스에서만 쓰기는 하는데 url을 분리하는건 어떻게 생각하세요?
제 생각에는 /api/users/login
에서 api는 오히려 클래스단에 분리해서 매핑시켜두는것이 더 어울리지 않을까해요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ㅎㅎ 사실 이거 다른 분들 의견이 없으셔서 그냥 놔두었는데
Controller 단에서 공통 url 묶어주는게 좋을 것 같네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 그리고 싸피하면서 ContextRoot 설정하는 방법도 있는데
api를 명시적으로 입력할지 ContextRoot로 api 넣을지 같이 고민해보면 좋을 것 같습니다,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
따로 api문서나 주석으로 처리하지 않는이상 명시적인게 더 나을 수도 있을 것 같아요 :)
final User user = requestUser.encode(passwordEncoder); | ||
validateDuplicatedEmail(user.email()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final User user = requestUser.encode(passwordEncoder); | |
validateDuplicatedEmail(user.email()); | |
validateDuplicatedEmail(user.email()); | |
final User user = requestUser.encode(passwordEncoder); |
제 생각이긴 한데 encoding하는 작업보다 email checking이 우선되어야 하지 않을까요?
email이 중복되었다면 굳이 encoding작업은 진행되지 않을 수도 있어 보여요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기존에 저장된 값이 인코딩되이 저장되어 있다고 생각해서 위와 같이 작성했습니다.
로직에 문제가 있는지 한번 봐야겠군요
|
||
private void validateArgumentNull(final Object argument) { | ||
if(isNull(argument)) { | ||
throw new IllegalArgumentException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
연관된 에러 메시지를 담아 전달하는게 좋아보이네요 :)
혹은 custom하셨으니 Null에 대한 input들 또한 custom해서 묶어볼수도있을것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기에는 CustomException을 안 넣었나 보네요
새로 추가하겠습니다. 👍
IDENTITY_NOT_FOUND(IdentityNotFoundException.class, HttpStatus.BAD_REQUEST, "Identity is not found"), | ||
PASSWORD_MISS_MATCH(PasswordMissMatchException.class, HttpStatus.BAD_REQUEST, "Password is miss match"); | ||
|
||
private final Class exceptionClass; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exception class까지 담는것 좋은거같아요 👍
public static UserErrorCode values(final UserBusinessException exception) { | ||
final Class<? extends UserBusinessException> exceptionClass = exception.getClass(); | ||
return Arrays.stream(values()) | ||
.filter(userErrorCode -> userErrorCode.exceptionClass.equals(exceptionClass)) | ||
.findFirst() | ||
.orElseThrow(IllegalArgumentException::new); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어떤 역할을 하는지 한번만 설명해주실수있을까용?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exception 만 넣으면 알아서 enum 상수 중 하나를 뱉어줍니다.
앞서 Exception 넣은 것을 이용해서 특정 Exception 값을 넣으면 알맞는 ErrorCode 상수를 반환해줘요!
@AuthenticationPrincipal final Long principal) { | ||
final User user = userUpdateService.update(userUpdateRequest.toEntity(), principal); | ||
final ResponseToken responseToken = tokenProvider.createToken(user); | ||
final UserResponse userResponse = UserResponse.fromUserWithToken(user, responseToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final UserResponse userResponse = UserResponse.fromUserWithToken(user, responseToken); | |
final UserResponse userResponse = UserResponse.fromUserAndToken(user, responseToken); |
개인적으로는 문맥상 And 가 더 나아보일듯 하네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오잉 왜 With 이 들어갔는지 제가 봐도 이해 안가네요
public static JwtErrorCode values(final AuthenticationException exception) { | ||
final Class<? extends AuthenticationException> exceptionClass = exception.getClass(); | ||
return Arrays.stream(values()) | ||
.filter(userErrorCode -> userErrorCode.exceptionClass.equals(exceptionClass)) | ||
.findFirst() | ||
.orElseThrow(IllegalArgumentException::new); | ||
} | ||
|
||
@Override | ||
public HttpStatus httpStatus() { | ||
return httpStatus; | ||
} | ||
|
||
@Override | ||
public String message() { | ||
return ERROR_CODE_MESSAGE; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오히려 모든 Error code가 재정의를 해야하는 상황이 오게 되었는데 조금더 좋은 방법은 없을까요?
관리의 편의성을 위한 부분이 뭔가 관리포인트의 증가로 온듯한?느낌이 들어서요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
가능하다면 Abstract Class 로 만들고 싶지만
Enum 클래스는 기본적으로 SomeEnum extends Enum
구조여서 클래스를 상속 못받더라고요
그래서 interface로 확장시켰고 이 부분은 해결하기 어렵더라고요
|
||
import java.util.Arrays; | ||
|
||
public enum SecurityErrorCode implements ErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분과 jwt의 error code의 분리는 좋은것 같기는 한데 둘을 합쳐도 되지않을까요? (그냥 제 생각입니당)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JwtErrorCode 는 Jwt관련 Exception이 나오도록 했고
SecurityErrorCode는 UserDetails 와 같은 Security에서 general한 요소들로 분리했습니다.
시큐리티 적용을 기준으로 jwt -> session으로 변경도 가능하다고 판단해서 분리시켰습니다!
|
||
@JsonTypeName("errors") | ||
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) | ||
public class SecurityErrorResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ErrorResponse를 상속받는 구조는 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ErrorCode와 같이 분리할까 생각하다 실현은 못했네요!!
사실 다른 ErrorResponse들도 구조가 아에 똑같아서 좋은 아이디어 같아요
체인지 전부 보셨다니;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exception 관리를 굉장히 철저히 관리하셨네요 ! 👍
@@ -1,6 +1,7 @@ | |||
plugins { | |||
id 'org.springframework.boot' version '2.5.3' | |||
id 'io.spring.dependency-management' version '1.0.11.RELEASE' | |||
id "org.asciidoctor.convert" version "1.5.9.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아스키 의사선생님 ... !?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ㅋㅋㅋㅋㅋㅋㅋㅋ restdocs 추가하면서 추가했습니다 👍
assertAll( | ||
() -> assertThat(SecurityErrorCode.values(new UserDetailsNullPointerException())).isNotNull() | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트할게 하나인데 assertAll
로 묶은건 통일성 있게 할려고 한건가요 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네네 그리고 시큐리티 에러는 도중에 추가될 가능성 염두해서 미리 처리했습니다.
Issue: #51
작업 내용
생성/변경 로직
개인 코멘트