Search code examples
javarefactoringdto

Validating user inputs on service methods in a cleaner way


In a project, we use service methods, there, we have to validate certain required inputs for our business logic to work:

public void exampleMethod(final UserDto user, String sthElse) {
  if (user.getId() == null) {
    throw new CustomHandledException("example");
  }
  if (sthElse == null) {
    throw new CustomHandledException("example");
  }

  GetUserResponseDto getUserResponse = client.getUserById(user.getId(), country);

  if (getUserResponse == null) {
    if (user.getGivenName() == null) {
      throw new CustomHandledException("example");
    }
    if (user.getEmail() == null) {
      throw new CustomHandledException("example");
    }
    CreateUserRequestDto createUserBody = UserMapper.toCreateBody(user);
    client.createUser(createUserBody);
    return;
  }

  if (user.getLocale().equals(getUserResponse.getUser().getProfile().getLocale())){
      return;
  }

  client.updateUser(user);
}

Even though the code isn't necessarily wrong and is quite understandable (for me) I feel like there is something odd there, do you have any suggestions for a cleaner code?

I tried to write clean code, however, it doesn't feel like it is clean.


Solution

  • We could go by AOP solutions or by extracting validations to a method as below

    public void exampleMethod(final UserDto user, String sthElse) {
            validateUser(user);
    
            if (sthElse == null) {
                throw new CustomHandledException("example");
            }
    
            GetUserResponseDto getUserResponse = client.getUserById(user.getId(), country);
    
            if (getUserResponse == null) {
                CreateUserRequestDto createUserBody = UserMapper.toCreateBody(user);
                client.createUser(createUserBody);
                return;
            }
    
            if (user.getLocale().equals(getUserResponse.getUser().getProfile().getLocale())){
                return;
            }
            // validations needs to be done before updating as well by convention
            // since validations were done while inserting
            client.updateUser(user);
        }
    
        private boolean validateUser(UserDto userDto) {
    
            //these declarations could be moved at class fields or constant
            Predicate<UserDto> customDtoCheck = user ->user.getGivenName().startsWith("text");
            Predicate<String> emailValidation = RequestValidator::validateEmail;
            Predicate notNull = RequestValidator::notNull;
    
            boolean validUser = notNull.test(userDto) &&
                                notNull.test(userDto.getId()) &&
                                notNull.test(userDto.getGivenName()) &&
                                notNull.test(userDto.getEmail()) &&
                                notNull.test(userDto.getLocale()) &&
                                emailValidation.test(userDto.getEmail()) &&
                                customDtoCheck.test(userDto);
            if (!validUser)
                throw new CustomHandledException("example");
    
            return validUser;
        }