I've been at this for hours but can't seem to untangle this. The error pertains to this segment of code:
(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 thenCompose
s, 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:
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()
));
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With