Why do I get a null here?

57 views Asked by At

So this piece of code

  public boolean getBoolean(Integer Id) {
    return Optional.of(Store.getMagazin(Id))
        .map(MagazinDO::getBoolean)
        .orElse(Boolean.FALSE);}

returns a null while this one doesn't

 public boolean getBoolean(Integer Id) {
    var magazin = store.getMagazin(Id);
    if (magazin != null) {
      boolean = magazin.getBoolean();
      return  boolean != null ? oppositeConversion : false;
    }
    return false;
  }

Why is this happening? I thought optional chaining can handle nulls.

1

There are 1 answers

0
Stefano Riffaldi On

As @Chaosfire said, there is no way that your getOppositePriceConversion(Integer catalogId) returns null, so if you meant that catalogStore.getCatalog throws a NullPointerException, you can handle it via Optional.ofNullable. I'm pretty sure about that, I enjoy to create some test case about it, it was a nice excuse to play with Mokito !

Given that structure:

package org.example;

import java.util.Optional;

public class OptionalNull {
    public static class CatalogService {
        private final CatalogStore catalogStore;

        public CatalogService(CatalogStore catalogStore) {
            this.catalogStore = catalogStore;
        }

        public boolean getOppositePriceConversion(Integer catalogId) {
            return Optional.of(catalogStore.getCatalog(catalogId))
                    .map(CatalogDO::oppositePriceConversion)
                    .orElse(Boolean.FALSE);
        }
        public boolean getOppositePriceConversionOfNullable(Integer catalogId) {
            return Optional.ofNullable(catalogStore.getCatalog(catalogId))
                    .map(CatalogDO::oppositePriceConversion)
                    .orElse(Boolean.FALSE);
        }
    }

    public interface CatalogStore {
        CatalogDO getCatalog(Integer catalogId);
    }

    public record CatalogDO(Integer id, Boolean oppositePriceConversion) {}
}

Then the tests:

package org.example.test;

import org.example.OptionalNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.example.OptionalNull.*;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class OptionalNullTest {
    @Mock
    private CatalogStore catalogStore;
    private CatalogService optionalNull;

    @BeforeEach
    void setUp() {
        optionalNull = new CatalogService(catalogStore);

        when(catalogStore.getCatalog(1)).thenReturn(null);
        when(catalogStore.getCatalog(2)).thenReturn(new CatalogDO(2, true));
        when(catalogStore.getCatalog(3)).thenReturn(new CatalogDO(3, false));
    }

    @Test
    void getOppositePriceConversionOfNullable() {
        assertThat(optionalNull.getOppositePriceConversionOfNullable(1))
                .isFalse();

        assertThat(optionalNull.getOppositePriceConversionOfNullable(2))
                .isTrue();

        assertThat(optionalNull.getOppositePriceConversionOfNullable(3))
                .isFalse();
    }

    @Test
    void getOppositePriceConversion() {
        assertThatThrownBy(() -> optionalNull.getOppositePriceConversion(1))
                .isExactlyInstanceOf(NullPointerException.class)
                .hasNoCause();

        assertThat(optionalNull.getOppositePriceConversion(2))
                .isTrue();

        assertThat(optionalNull.getOppositePriceConversion(3))
                .isFalse();
    }
}

fyi: java 17, junit 5.10.1, assterj 3.25.1, mokito 5.2.0