@Test
  public void projection_nulls() {
    assumeFeature(Feature.QUERY_WITH_PROJECTION);
    final PersonGenerator generator = new PersonGenerator();
    insert(generator.next().withId("id1").withFullName("John").withNickName(Optional.empty()).withAge(21).withBestFriend(Optional.empty()));
    insert(generator.next().withId("id2").withFullName("Mary").withNickName(Optional.empty()).withAge(22).withBestFriend(Optional.empty()));
    insert(generator.next().withId("id3").withFullName("Emma").withNickName(Optional.empty()).withAge(23).withBestFriend(Optional.empty()));

    Checkers.check(repository().findAll().select(person.nickName)
            .fetch())
            .hasContentInAnyOrder(Optional.empty(), Optional.empty(), Optional.empty());

    // with tuple
    Checkers.check(repository().findAll().select(Collections.singleton(person.nickName)).map(x -> x.get(person.nickName))
            .fetch())
            .hasContentInAnyOrder(Optional.empty(), Optional.empty(), Optional.empty());

    // normally bestFriend.hobby is Projection<String> but with person.bestFriend.hobby it becomes Projection<Optional<Sting>> because person.bestFriend is optional
    Checkers.check(repository().findAll().select(person.bestFriend.value().hobby)
            .asOptional()
            .fetch())
            .hasContentInAnyOrder(Optional.empty(), Optional.empty(), Optional.empty());

    // same as before but with tuple
    Checkers.check(repository().findAll().select(Collections.singleton(person.bestFriend.value().hobby))
            .map(x -> Optional.ofNullable(x.get(person.bestFriend.value().hobby)))
            .fetch())
            .hasContentInAnyOrder(Optional.empty(), Optional.empty(), Optional.empty());

    Checkers.check(repository().findAll().select(person.nickName, person.bestFriend.value().hobby)
            .map((nickName, hobby) -> nickName.orElse("") + (hobby == null ? "" : hobby))
            .fetch())
            .hasContentInAnyOrder("", "", "");

    Checkers.check(repository().findAll().select(Arrays.asList(person.nickName, person.bestFriend.value().hobby))
            .map(tuple -> tuple.get(person.nickName).orElse("") + Optional.ofNullable(tuple.get(person.bestFriend.value().hobby)).orElse(""))
            .fetch())
            .hasContentInAnyOrder("", "", "");
  }
Edge case for empty/non-empty string for null values.
{@code string.notEmpty} should not return empty / missing values
criteria/common/test/org/immutables/criteria/personmodel/AbstractPersonTest.java