Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

no instance(s) of type variable(s) U exist so that Foo conforms to CompletionStage<U>

I've been at this for hours but can't seem to untangle this. The error pertains to this segment of code:

enter image description here

(Full code at bottom of this question. I'm using screenshots to show the issue visually.)

The error itself is:

no instance(s) of type variable(s) U exist so that GetUsersForAdAccountResponse conforms to CompletionStage

At the very beginning of the chain of thenComposes, I erased the return and used IntelliJ's "Introduce local variable..." feature to see what type the entire chain (up to and including line 1118) is returning:

enter image description here

The result was a

final CompletionStage<U> uCompletionStage = ...

But you can see that the return type of the encompassing method is

public CompletionStage<GetUsersForAdAccountResponse> ...

What is preventing the compiler from inferring GetUsersForAdAccountResponse? (Again, normally there is a return here.)

I have also tried introducing a local variable at every thenCompose along the way, and they all seem correct. Each yields a CompletionStage<Foo>, for which the next thenCompose supplies a lambda expecting Foo and yields a CompletionStage<Bar>, and so on. (In one reorganization of the code I did see a nested CompletionStage<CompletionStage<Foo>> but I think that was an artifact of my own rewriting.)


I don't know if it will help, but here is the entire method:

  @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()
        ));
  }
like image 738
slackwing Avatar asked Aug 17 '18 06:08

slackwing


1 Answers

The last thenCompose in the chain should be thenApply. The function passed to it is returning a GetUsersForAdAccountResponse which is not CompletionStage.

thenCompose is the flatMap of CompletableFuture. It takes a function that returns a CompletionStage and flattens the result.

like image 142
Misha Avatar answered Nov 04 '22 06:11

Misha