programing

모노가 비어 있는 경우에만 작업을 수행하고 비어 있지 않은 경우에는 오류를 발생시키는 방법

linuxpc 2023. 7. 10. 22:06
반응형

모노가 비어 있는 경우에만 작업을 수행하고 비어 있지 않은 경우에는 오류를 발생시키는 방법

Spring WebFlux를 사용하기 위해 프로젝트를 변환하려고 하는데 기본적인 비즈니스 로직을 사용하는 데 문제가 발생하고 있습니다.레코드 검색/유지를 담당하는 저장소 계층과 애플리케이션의 비즈니스 규칙을 담당하는 서비스 계층이 있습니다.서비스 계층에서 수행할 작업은 지정된 사용자 이름에 대한 사용자가 이미 있는지 확인하는 것입니다.그렇다면 오류로 대응하고 싶습니다.그렇지 않으면 삽입을 허용하고 싶습니다.

저장소 계층에서 사용자 이름으로 사용자를 찾고 찾지 못하면 빈 Mono를 반환하는 메서드를 호출합니다.이것은 예상대로 작동하지만, 저는 flatMap과 (defaultIfEmpty와 swithIfEmpty)의 다양한 조합을 시도했지만 컴파일/빌드를 할 수 없습니다.

    public Mono<User> insertUser(User user) {
        return userRepository.findByUsername(user.username())
            .flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
            .switchIfEmpty(userRepository.insertUser(user));
    }

제가 받고 있는 오류는Mono<Object> cannot be converted to Mono<User>그래서swithIfEmpty적절한 유형을 반영하지 못하는 것 같고 캐스팅도 제대로 되지 않는 것 같습니다.

추가 테스트 후 동료 개발자들의 반응을 고려하여 다음 솔루션에 도달했습니다.

    public Mono<User> insertUser(User user) {
        return userRepository.findByUsername(user.username())
            .flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
            .switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))
            .cast(User.class);
    }

토마스가 말했듯이, 컴파일러는 혼란스러워하고 있었습니다.제 추측은 왜냐하면flatMap오류가 있는 모노를 반환하고 있었습니다.switchIfEmpty사용자가 있는 모노를 반환하여 개체가 있는 모노로 돌아갑니다(따라서 추가)..cast컴파일할 연산자).

다른 추가 사항은 다음을 추가하는 것이었습니다.Mono.defer에서switchMap그렇지 않으면,switchIfEmpty항상 총을 쏘고 있었습니다.

저는 여전히 다른 제안/대안에 대해 열려 있습니다(이것이 상당히 일반적인 필요/패턴인 것처럼 보이기 때문입니다).

형식 매개 변수가 있는 추상 클래스를 사용하고 있습니다.E그래서 사용할 수 없었습니다..cast(E.class)우리의 해결책은

private Mono<E> checkIfStatementExists(E statement) {
    return this.statementService.getByStatementRequestId(statement.getStatementRequestId())
            .flatMap(sr -> Mono.<E>error(new ValidationException("Statement already exists for this request!")))
            .switchIfEmpty(Mono.just(statement));
}

이 문제는 다음 주에 동료들과 상의해야 할 것 같습니다.

편집. 동료들과 상의를 해보았는데 업데이트된 코드는 위와 같습니다.

이 컴파일러 오류가 발생하는 이유는 다음과 같습니다.

flatmap완료된 내용을 가져옵니다.Mono추론할 수 있는 모든 유형으로 변환하려고 합니다. Mono.error유형을 포함하며 이 유형은Object.

한 가지 방법은 대신 논리를 플랫 맵으로 이동하는 것일 수 있습니다.

// This is just example code using strings instead of repos
public Mono<String> insertUser(String user) {
    return Mono.just(user)
            // Here we map/convert instead based on logic
            .flatMap(__ -> {
                if (__.isEmpty())
                    return Mono.error(new IllegalArgumentException("User already exists with username [" + user + "]"));
                return Mono.just(user);
            }).switchIfEmpty(Mono.just(user));
}

switchIfEmpty논리적인 결정을 내리는 데는 그다지 좋지 않습니다.문서에는 다음과 같이 기술되어 있습니다.

데이터 없이 모노가 완료된 경우 대체 모노로 폴백

아무것도 얻지 못하면 다른 것으로 되돌아가는 것에 가깝기 때문에 데이터 흐름을 유지할 수 있습니다.

또한

Mono.empty().doOnNext(o -> {
        throw new IllegalArgumentException("User already exists with username [" + o + "]");
    }).switchIfEmpty(Mono.just("hello")).subscribe(System.out::println);

같은 문제를 겪었고 결국 아래와 같은 일을 하게 되었습니다.

참고:이는 유형 캐스트가 필요하지 않으며 두 시나리오 모두에서 작동합니다.

  • 데이터베이스에 요소가 이미 있는 경우 오류를 발생시킵니다.

  • 요소를 삽입하고 그렇지 않으면 Mono를 반환합니다.

      public Mono<UserDTO> insertUser(User user) {
         return this.userRepository.findByUsername(user.getUsername())
                 .flatMap(foundUser-> null != foundUser ? Mono
                         .error(new UserAlreadyExistsException(ExceptionsConstants.USER_ALREADY_EXISTS_EXCEPTION))
                         : Mono.just(user))
                 .switchIfEmpty(this.userRepository.save(user))
                 .map(userCreated -> copyUtils.createUserDTO(userCreated));
      }
    

를사는대신을 사용하는 에.Mono::cast모노의 유형을 변경하기 위해, 이것은 다음의 유형을 지정함으로써 해결될 수 있습니다.Mono.error약간의 자바 일반 마법을 사용하는 것의 형태로.Mono.<User>error(...).flatMap하지 않는 . null을 수신합니다.

이는 다음과 같습니다.

public Mono<User> insertUser(User user) {
    return userRepository.findByUsername(user.username())
        .flatMap(__ -> Mono.<User>error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
        .switchIfEmpty(userRepository.insertUser(user));
}

언급URL : https://stackoverflow.com/questions/58127132/how-to-perform-an-action-only-if-the-mono-is-empty-and-throw-an-error-if-not-emp

반응형