varnie
varnie

Reputation: 2595

rx-java2: how to safely invoke flatMapSingle

I am struggling with rx-java2. Basically, I cannot safely "escape" from Maybe to Single and continue the logic flow for the rest items. So here's my simplified code, demonstrating my question:

  public Flowable<Long> run() {
    //let's assume this is my "input" data
    List<UserTask> userTasks;

    return Single.just(userTasks)
        .flatMapPublisher(Flowable::fromIterable)
         // userRepository.getUser returns a Maybe<User>
        .map((UserTask ut) -> userRepository.getUser(ut.getName())
                //search for user
                //if not found, return a dummy user object
                .defaultIfEmpty(User.newBuilder().build())
                //leave dummy user objects only
                .filter((User u) -> u.getName() == null)
                //for each dummy user object return a corresponding user task
                .map(u -> ut)
        )
        .flatMapSingle(Maybe::toSingle)
        .flatMap((UserTask mt) -> {
          // return user related to user task, implementation does not matter
          return Flowable.just(User.newBuilder().build());
        })
        .flatMapSingle(this::saveUser);
  }

  private Single<Long> saveUser(User u) {
    return userRepository.saveUser(m).subscribeOn(Schedulers.io());
  }

I tried to provide types where needed to ease the understanding. The problem here is that in case the Maybe is empty, this line (I guess) .flatMapSingle(Maybe::toSingle) throws an exception NoSuchItemException and the flow execution terminates. Is it possible to improve my code so that if Maybe value is absent, the flow skips this item and goes on?

Please let me know if there's some missing details, I'll provide them.

Upvotes: 1

Views: 1385

Answers (1)

akarnokd
akarnokd

Reputation: 69997

Not sure why you chose this convoluted set of operators. Try this:

public Flowable<Long> run() {
    //let's assume this is my "input" data
    List<UserTask> userTasks;

    return 
    Flowable.fromIterable(userTasks)
     // userRepository.getUser returns a Maybe<User>
    .flatMapMaybe((UserTask ut) -> userRepository.getUser(ut.getName())
            .defaultIfEmpty(User.newBuilder().build())
            .filter((User u) -> u.getName() == null)
            .map(u -> ut)
    )
    .map((UserTask mt) -> {
      // return user related to user task, implementation does not matter
      return User.newBuilder().build();
    })
    .flatMapSingle(this::saveUser);
}

private Single<Long> saveUser(User u) {
   return userRepository.saveUser(m).subscribeOn(Schedulers.io());
}

The documentation details the type conversions between reactive types.

Upvotes: 4

Related Questions