не существует экземпляра (ов) переменной (переменных) типа U, так что Foo соответствует CompletionStage‹U›

Я был в этом в течение нескольких часов, но, кажется, не могу распутать это. Ошибка относится к этому сегменту кода:

введите здесь описание изображения

(Полный код внизу этого вопроса. Я использую скриншоты, чтобы визуально показать проблему.)

Сама ошибка:

экземпляр(ы) переменной(ов) типа U не существует, так что GetUsersForAdAccountResponse соответствует CompletionStage

В самом начале цепочки thenCompose я стер return и использовал функцию IntelliJ "Ввести локальную переменную...", чтобы увидеть, какой тип возвращает вся цепочка (до строки 1118 включительно). :

введите здесь описание изображения

В результате

final CompletionStage<U> uCompletionStage = ...

Но вы можете видеть, что возвращаемый тип охватывающего метода:

public CompletionStage<GetUsersForAdAccountResponse> ...

Что мешает компилятору вывести GetUsersForAdAccountResponse? (Опять же, обычно здесь стоит return.)

Я также пытался вводить локальную переменную в каждые thenCompose по пути, и все они кажутся правильными. Каждый дает CompletionStage<Foo>, для которого следующий thenCompose предоставляет лямбду, ожидающую Foo, и дает CompletionStage<Bar>, и так далее. (В одной реорганизации кода я увидел вложенный CompletionStage<CompletionStage<Foo>>, но я думаю, что это был артефакт моего собственного переписывания.)


Не знаю, поможет ли, но вот весь метод:

  @Override
  public CompletionStage<GetUsersForAdAccountResponse> getUsersForAdAccount(
      RequestContext context, GetUsersForAdAccountRequest request) {

    Uuid adAccountId = request.getAdAccountId();

    return verifyAuthorization(context,
        PortcullisTemplates.Action.GET_USERS_FOR_AD_ACCOUNT.getName(),
        portcullisTemplates.topOrganizationResource())
        .thenCompose(auditLogPrincipal -> jdbiExecutor.executeInTransaction(handler -> {

              // We purposely safeguard the account lookup as well behind Portcullis.
              AdAccountDao adAccountDao = handler.attach(AdAccountDao.class);
              if (adAccountDao.getAdAccountById(adAccountId) == null) {
                throw new ValidationException(SERVICE_NAME,
                    "Ad account not found: " + UuidUtils.toString(adAccountId));
              }

              AdAccountRoleUserMappingDao roleDao = handler.attach(AdAccountRoleUserMappingDao.class);

              List<String> roleNames = request.getRoleNamesList();
              return roleNames.isEmpty() ?
                     roleDao.getAdAccountRoleUserMappingsByAdAccount(adAccountId) :
                     roleDao.getAdAccountRoleUserMappingsByAdAccountAndRoles(adAccountId, roleNames);

        })).thenCompose(adAccountRoleUserMappings -> jdbiExecutor.execute(UserDao.class, userDao -> {
          return userDao
              .getUsersBy]UserIds(
                  adAccountRoleUserMappings.stream()
                      .map(AdAccountRoleUserMapping::userId)
                      .collect(Collectors.toList())
              ).stream()
                  .collect(Collectors.toMap(
                      User::userId,
                      user -> new EncryptedFieldsBuilder()
                          .firstName(user.encryptedFirstName())
                          .lastName(user.encryptedLastName())
                          .email(user.encryptedEmail())
                          .build()
              ));
        }).thenCompose(
            userEncryptedFields -> padlockService.decryptUserAccounts(userEncryptedFields)
        ).thenCompose(decryptedUsers -> GetUsersForAdAccountResponse.newBuilder()
            .addAllUserWithRole(
                adAccountRoleUserMappings.stream()
                    .filter(mapping -> decryptedUsers.containsKey(mapping.userId()))
                    .map(mapping -> UserWithRole.newBuilder()
                        .setAccount(decryptedUsers.get(mapping.userId()))
                        .setRoleName(mapping.roleName())
                        .build())
                    .collect(Collectors.toSet())
            ).build()
        ));
  }

person slackwing    schedule 17.08.2018    source источник
comment
Похоже, что последний thenCompose на самом деле должен быть thenApply. Или, пожалуйста, предоставьте подпись метода build() для всего, что возвращает GetUsersForAdAccountResponse.newBuilder().   -  person Misha    schedule 17.08.2018
comment
Так много всего происходит ПОСЛЕ возвращения, и фьючерсы на плоских картах, и шаблон Дао, кажется, я не так готов работать с Java, как я думал.   -  person JohanLarsson    schedule 17.08.2018
comment
@Миша - Омфг. Первые несколько часов я использовал thenApply, но теперь вижу, что что-то еще было не так. Я сдался и перешел к thenCompose, что, казалось, вызывало более ограниченную ошибку. Играя с этим, я по незнанию исправил первоначальную проблему, но никогда не возвращался к thenApply. Теперь компилируется нормально. Спасибо, и не стесняйтесь добавлять ответ, чтобы я мог принять.   -  person slackwing    schedule 17.08.2018


Ответы (1)


Последний thenCompose в цепочке должен быть thenApply. Переданная ей функция возвращает GetUsersForAdAccountResponse, а не CompletionStage.

thenCompose является flatMap из CompletableFuture. Он принимает функцию, которая возвращает CompletionStage и сглаживает результат.

person Misha    schedule 17.08.2018