Skip to content
Advertisement

Update objects’s state in Reactor

Given the following method:

private Mono<UserProfileUpdate> upsertUserIdentifier(UserProfileUpdate profileUpdate, String id){
    return userIdentifierRepository.findUserIdentifier(id)
            .switchIfEmpty(Mono.defer(() -> {
                profileUpdate.setNewUser(true);
                return createProfileIdentifier(profileUpdate.getType(), id);
            }))
            .map(userIdentifier -> {
                profileUpdate.setProfileId(userIdentifier.getProfileId());
                return profileUpdate;
            });
}

switchIfEmpty and map operators mutate the profileUpdate object. Is it safe to mutate in switchIfEmpty operator? Regarding map, if I have understood correctly, this is not safe and object profileUpdate must be immutable, right? eg:

private Mono<UserProfileUpdate> upsertUserIdentifier(UserProfileUpdate profileUpdate, String id){
        return userIdentifierRepository.findUserIdentifier(id)
                .switchIfEmpty(Mono.defer(() -> {
                    profileUpdate.setNewUser(true);
                    return createProfileIdentifier(profileUpdate.getType(), id);
                }))
                .map(userIdentifier -> profileUpdate.withProfileId(userIdentifier.getProfileId()));
    }

Later in the chain, another method mutates the object:

public Mono<UserProfileUpdate> transform(UserProfileUpdate profUpdate) {
        if (profUpdate.isNewUser()) {
            profUpdate.getAttributesToSet().putAll(profUpdate.getAttributesToSim());
        } else if (!profUpdate.getAttributesToSim().isEmpty()) {
            return  userProfileRepository.findUserProfileById(profUpdate.getProfileId())
                    .map(profile -> {
                        profUpdate.getAttributesToSet().putAll(
                                collectMissingAttributes(profUpdate.getAttributesToSim(), profile.getAttributes().keySet()));
                        return profUpdate;
                    });
        }
        return Mono.just(profUpdate);
    }

The above methods are called as follows:

  Mono.just(update)
  .flatMap(update -> upsertUserIdentifier(update, id))
  .flatMap(this::transform)

Advertisement

Answer

Nebulous answer, but… it depends!

The danger of mutating an input parameter in the returned Mono or Flux comes from the fact that said Mono or Flux could be subscribed multiple times. In such a case, suddenly you have a shared resource on your hands, and it can lead to puzzling issues.

But if the methods in question are called from a well controlled context, it can be safe.

In your case, flatMap ensures that the inner publishers are subscribed to only once. So as long as you only use these methods inside such flatMaps, they can safely mutate their input parameter (it is kept in the scope of the flatmapping function).

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement