Skip to content
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

Merged
merged 40 commits into from Oct 2, 2021
Merged

Conversation

kwj1270
Copy link

@kwj1270 kwj1270 commented Sep 19, 2021

Issue: #51

작업 내용

  • Exception 관련되어서 리팩토링 했습니다.
  • RestControllerAdvice 적용

생성/변경 로직

  • RestControllerAdvice 생성
  • 커스텀 Exception 생성
  • 익셉션 필터 및 관련 코드들 적용

개인 코멘트

  • ExceptionTranslationFilter 적용하려 했으나 Interceptor 단계에서 동작하는 필터로 동작을 안하네요
  • RestDocs / log4j2 적용은 내일 올릴 다음 pr에 하겠습니다.

@kwj1270 kwj1270 added the woozi 우지의 이슈 label Sep 19, 2021
@kwj1270 kwj1270 self-assigned this Sep 19, 2021
@codecov-commenter
Copy link

codecov-commenter commented Sep 19, 2021

Codecov Report

Merging #53 (05d538f) into kwj1270 (c86ab55) will increase coverage by 1.30%.
The diff coverage is 100.00%.

Impacted file tree graph

@@              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              
Impacted Files Coverage Δ
...m/study/realworld/domain/user/domain/Password.java 100.00% <ø> (ø)
...udy/realworld/domain/user/dto/UserJoinRequest.java 100.00% <ø> (ø)
.../realworld/global/jpa/config/JpaConfiguration.java 100.00% <ø> (ø)
.../exception/JwtProviderNotSupportTypeException.java 100.00% <ø> (ø)
...orld/domain/auth/application/AuthLoginService.java 100.00% <100.00%> (ø)
...orld/domain/auth/infrastructure/TokenProvider.java 100.00% <100.00%> (ø)
...dy/realworld/domain/auth/presentation/AuthApi.java 100.00% <100.00%> (ø)
...world/domain/user/application/UserFindService.java 100.00% <100.00%> (ø)
...world/domain/user/application/UserJoinService.java 100.00% <100.00%> (ø)
...rld/domain/user/application/UserUpdateService.java 100.00% <100.00%> (ø)
... and 54 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c86ab55...05d538f. Read the comment docs.

Copy link
Member

@jinyoungchoi95 jinyoungchoi95 left a 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()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

람다식으로 다시 변경하게 된 이유가 있을까용?

Copy link
Author

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 {
Copy link
Member

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는 오히려 클래스단에 분리해서 매핑시켜두는것이 더 어울리지 않을까해요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅎㅎ 사실 이거 다른 분들 의견이 없으셔서 그냥 놔두었는데
Controller 단에서 공통 url 묶어주는게 좋을 것 같네요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 그리고 싸피하면서 ContextRoot 설정하는 방법도 있는데
api를 명시적으로 입력할지 ContextRoot로 api 넣을지 같이 고민해보면 좋을 것 같습니다,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

따로 api문서나 주석으로 처리하지 않는이상 명시적인게 더 나을 수도 있을 것 같아요 :)

Comment on lines +24 to +25
final User user = requestUser.encode(passwordEncoder);
validateDuplicatedEmail(user.email());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final User user = requestUser.encode(passwordEncoder);
validateDuplicatedEmail(user.email());
validateDuplicatedEmail(user.email());
final User user = requestUser.encode(passwordEncoder);

제 생각이긴 한데 encoding하는 작업보다 email checking이 우선되어야 하지 않을까요?
email이 중복되었다면 굳이 encoding작업은 진행되지 않을 수도 있어 보여요

Copy link
Author

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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연관된 에러 메시지를 담아 전달하는게 좋아보이네요 :)
혹은 custom하셨으니 Null에 대한 input들 또한 custom해서 묶어볼수도있을것 같아요

Copy link
Author

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exception class까지 담는것 좋은거같아요 👍

Comment on lines +26 to +32
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);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 역할을 하는지 한번만 설명해주실수있을까용?

Copy link
Author

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final UserResponse userResponse = UserResponse.fromUserWithToken(user, responseToken);
final UserResponse userResponse = UserResponse.fromUserAndToken(user, responseToken);

개인적으로는 문맥상 And 가 더 나아보일듯 하네요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오잉 왜 With 이 들어갔는지 제가 봐도 이해 안가네요

Comment on lines +27 to +43
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;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오히려 모든 Error code가 재정의를 해야하는 상황이 오게 되었는데 조금더 좋은 방법은 없을까요?
관리의 편의성을 위한 부분이 뭔가 관리포인트의 증가로 온듯한?느낌이 들어서요

Copy link
Author

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분과 jwt의 error code의 분리는 좋은것 같기는 한데 둘을 합쳐도 되지않을까요? (그냥 제 생각입니당)

Copy link
Author

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorResponse를 상속받는 구조는 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorCode와 같이 분리할까 생각하다 실현은 못했네요!!
사실 다른 ErrorResponse들도 구조가 아에 똑같아서 좋은 아이디어 같아요

@kwj1270
Copy link
Author

kwj1270 commented Sep 20, 2021

체인지 전부 보셨다니;;
이게 기존 PR도 열려있고 어떻게 PR보내려고 우회했더니 그렇게 되었나보네요 ㅠㅡㅠ 감사합니다. 오리님
오리님 코드도 세밀하게 신경쓰시는게 느껴져서 저도 덩달아 영향 받은 것 같네요.
저희 끝까지 마무리 열심히 해보도록 합시다.

@kwj1270 kwj1270 changed the title [kwj1270-issue50] Exception 관련 리팩토링 [kwj1270-issue51] Exception 관련 리팩토링 Sep 20, 2021
Copy link
Member

@hoony-lab hoony-lab left a 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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아스키 의사선생님 ... !?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋ restdocs 추가하면서 추가했습니다 👍

Comment on lines +14 to +16
assertAll(
() -> assertThat(SecurityErrorCode.values(new UserDetailsNullPointerException())).isNotNull()
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트할게 하나인데 assertAll로 묶은건 통일성 있게 할려고 한건가요 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네네 그리고 시큐리티 에러는 도중에 추가될 가능성 염두해서 미리 처리했습니다.

@kwj1270 kwj1270 merged commit 0b1eef6 into kwj1270 Oct 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
woozi 우지의 이슈
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants