3

How can I convert Optional List object from one type to another, for an example

Optional<List<ProductMultipleOptionViewModel>> productOptionType1 // One type

Optional<List<ProductMultipleOption>> productOptionType2 // Other type

ProductMultipleOptionViewModel

Type 1

@Introspected
public record ProductMultipleOptionViewModel(
        ProductOptionViewModel productOption,
        String optionName) {
}

Type 2

 @Introspected
    public record ProductMultipleOption(
            ProductOptionViewModel productOption,
            String optionName) {
    }

I want to convert from Optional<List<ProductMultipleOption>>to other Optional<List<ProductMultipleOptionViewModel>>. I tried the below code

Optional<List<ProductMultipleOptionViewModel>> conveertItem = Optional.ofNullable(product.getProductMultipleOption())
                .orElseGet(null)
                .stream()
                .map(option -> {
                    return new ProductMultipleOptionViewModel(
                            ProductOptionViewModel.valueOf(//Access the option value//), //access the option value//
                    );
                })
                .collect(Collectors.toList());

With the above code, I am not able to access the option value inside map method

If product.getProductMultipleOption() is null return null or empty list.

k314159
  • 5,051
  • 10
  • 32
San Jaisy
  • 15,327
  • 34
  • 171
  • 290
  • 1
    I don't understand what you are trying to do. Can you show some sample inputs and outputs of what you are trying to convert? – Sweeper Mar 12 '21 at 09:29
  • You can map each option object in the list to Optional using map – JHDev Mar 12 '21 at 09:33
  • ... more or less, you would need to `map` it judiciously using `Optional#map` and `Stream#map` depending upon what you are looking for as an output. – Naman Mar 12 '21 at 09:56
  • @Sweeper updated the question, please have a look – San Jaisy Mar 12 '21 at 10:08
  • Does `product.getProductMultipleOption()` return an optional list, or a list that can be `null`? – Sweeper Mar 12 '21 at 10:19
  • It returns list that can be null – San Jaisy Mar 12 '21 at 10:26
  • 1
    @SanJaisy why make it complicated to wrap things around with `Optional` in this case? Just perform a null check and make use of the empty List for the type that you want as a result. – Naman Mar 12 '21 at 10:45

3 Answers3

6

You should rarely use Optional and Collections (like List or Set) together. Instead you should work with empty Collections. Also keep in mind that Optionals should not really be used for conditional logic, but rather as return values.

Either using a normal if statement:

List<ProductMultipleOptionViewModel> conveertItem = new ArrayList<>(); 
if (product.getProductMultipleOption() != null) {
   for(ProductMultipleOption option : product.getProductMultipleOption()) {
       conveertItem.add(new ProductMultipleOptionViewModel(
          ProductOptionViewModel.valueOf(option)
       ));
   }
}

Another variant:

List<ProductMultipleOption> list = product.getProductMultipleOption();
if (list == null) {
    list = Collections.emptyList();
}
List<ProductMultipleOptionViewModel> conveertItem = new ArrayList<>(); 
for(ProductMultipleOption option : list) {
   conveertItem.add(new ProductMultipleOptionViewModel(
      ProductOptionViewModel.valueOf(option)
   ));
}

Or if you really want to use Streams and Optionals (matter of taste):

List<ProductMultipleOptionViewModel> conveertItem = Optional.ofNullable(product.getProductMultipleOption())
    .map(List::stream)
    .orElseGet(Stream::empty)
    .map(option -> new ProductMultipleOptionViewModel(
        ProductOptionViewModel.valueOf(option)
    ))
    .collect(Collectors.toList());

Now that's a lot of code for simply converting a nullable List. So why not return an empty List in the first place? Change product.getProductMultipleOption() to something like this:

public List<ProductMultipleOption> getProductMultipleOption() {
    List<ProductMultipleOption> list = ...; // your current logic for getting the list
    return list == null ? Collections.emptyList() : list;
}

That way you never have to worry about null checks. Because you're simply working with an empty collection wherever you're calling getProductMultipleOption().

Lino
  • 19,604
  • 6
  • 47
  • 65
1

It helps to think about dealing with nulls/empty optionals separately from dealing with the list. The code below deals with nulls using the Optional.map() method, which returns an empty optional (of the appropriate return type) if the given argument is empty; otherwise, it applies the mapping function on the list.

Optional<List<ProductMultipleOptionViewModel>> convertedItem =
        Optional.ofNullable(product.getProductMultipleOption())
                .map(list -> list.stream()
                        .map(option -> new ProductMultipleOptionViewModel(
                                option.productOption(),
                                option.optionName()))
                        .collect(Collectors.toList()));
k314159
  • 5,051
  • 10
  • 32
0

Might not be the best way to do whatever you're doing... but to answer your question if you're trying to work with what you've got and keep it minimal:

private List<ProductMultipleOption> getProductOptionViewModelList() {
    /* simulating return of a list that could be null. */
    return null;
}
private Optional<List<ProductMultipleOption>> getProductMultipleOptionNull() {
    /* simulating return of an optional list. */
    return Optional.empty();
}
private static class ProductOptionViewModel { }
public record ProductMultipleOptionViewModel(
        ProductOptionViewModel productOption,
        String optionName) {
}
public record ProductMultipleOption(
        ProductOptionViewModel productOption,
        String optionName) {
}

/*
 Create your own methods to convert the models.

 Replace the variables with whichever method is available to get the name:
        (inputOption.productOption, inputOption.optionName)
        (inputOption.productOption(), inputOption.optionName())
.           (inputOption.getProductOption(), inputOption.getOptionName())
*/

private ProductMultipleOptionViewModel convertToMultipleOptionViewModel(
        ProductMultipleOption inputOption) {
    return new ProductMultipleOptionViewModel(
            inputOption.productOption,
            inputOption.optionName);
}
private ProductMultipleOption convertToMultipleOption(
        ProductMultipleOptionViewModel inputOption) {
    return new ProductMultipleOption(
            inputOption.productOption,
            inputOption.optionName);
}


/*
If the list you're getting is Optional<List<ProductOptionViewModel>>
    and you want List<ProductMultipleOptionViewModel>
*/
List<ProductMultipleOptionViewModel> convertedFromOptionalList =
        getProductMultipleOptionNull()
            .stream()
            .flatMap(Collection::stream)
            .map(this::convertToMultipleOptionViewModel)
            .toList();

/*
If the list you're getting is List<ProductOptionViewModel>
    and you want List<ProductMultipleOptionViewModel>
*/
List<ProductMultipleOptionViewModel> convertedFromNullableList = Optional
        .ofNullable(getProductOptionViewModelList())
            .stream()
            .flatMap(Collection::stream)
            .map(this::convertToMultipleOptionViewModel)
            .toList();

/*
If for some reason you're trying to get the list as
    Optional<List<ProductOptionViewModel>> you can wrap
    them with Optional.of() :
*/
Optional<List<ProductMultipleOptionViewModel>> convertedFromOptionalList = Optional
        .of(Optional.ofNullable(getProductOptionViewModelList())
            .stream()
            .flatMap(Collection::stream)
            .map(this::convertToMultipleOptionViewModel)
            .toList());

Optional<List<ProductMultipleOptionViewModel>> convertedFromNullableList = Optional
        .of(getProductMultipleOptionNull()
            .stream()
            .flatMap(Collection::stream)
            .map(this::convertToMultipleOptionViewModel)
            .toList());
IvanEOD
  • 1
  • 1