Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream API for JsonNullable wrapper #56

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions src/main/java/org/openapitools/jackson/nullable/JsonNullable.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

public class JsonNullable<T> implements Serializable {

private static final long serialVersionUID = 1L;

private static final JsonNullable<?> UNDEFINED = new JsonNullable<>(null, false);
private static final JsonNullable<?> NULL = new JsonNullable<>(null, true);

private final T value;

private final boolean isPresent;

private JsonNullable(T value, boolean isPresent) {
Expand All @@ -32,6 +33,11 @@ public static <T> JsonNullable<T> undefined() {
return t;
}

@SuppressWarnings("unchecked")
public static <T> JsonNullable<T> ofNull() {
return (JsonNullable<T>) NULL;
}

/**
* Create a <code>JsonNullable</code> from the submitted value.
*
Expand All @@ -43,6 +49,31 @@ public static <T> JsonNullable<T> of(T value) {
return new JsonNullable<>(value, true);
}

/**
* Returns wrapper of either UNDEFINED or NULL state
*
* @param value the value
* @param <T> type of value inside
* @return <code>JsonNullable</code> in UNDEFINED or NULL state
*/
public static <T> JsonNullable<T> ofMissable(T value) {
return new JsonNullable<>(value, value != null);
}

public <R> JsonNullable<R> flatMap(Function<? super T, ? extends JsonNullable<R>> mapper) {
if (isNonNull()) {
return mapper.apply(value);
}
return isNull() ? JsonNullable.ofNull() : JsonNullable.undefined();
}

public <R> JsonNullable<R> map(Function<? super T, ? extends R> mapper) {
if (isNonNull()) {
return JsonNullable.ofMissable(mapper.apply(value));
}
return isNull() ? JsonNullable.ofNull() : JsonNullable.undefined();
}

/**
* Obtain the value of this <code>JsonNullable</code>.
*
Expand Down Expand Up @@ -84,6 +115,25 @@ public void ifPresent(
}
}

public boolean isNull() {
return isPresent && value == null;
}

public boolean isNonNull() {
return isPresent && value != null;
}

/**
* If non-null value is present, performs an action with the value
*
* @param action The action performed with value
*/
public void ifNotNull(Consumer<T> action) {
if (isNonNull()) {
action.accept(value);
}
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
Expand All @@ -108,4 +158,4 @@ public int hashCode() {
public String toString() {
return this.isPresent ? String.format("JsonNullable[%s]", value) : "JsonNullable.undefined";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.openapitools.jackson.nullable;

import junit.framework.TestCase;
import org.junit.Test;

import static junit.framework.TestCase.*;

public class JsonNullableStreamApiTest {


@Test
public void shouldReturnUndefinedAfterStream() {
final BigDto bigDto = new BigDto(null);

final JsonNullable<String> accessedValue = JsonNullable.ofMissable(bigDto)
.map(BigDto::getChild)
.map(ChildOfBigDto::getGrandChild);

assertEquals(accessedValue, JsonNullable.undefined());
}


@Test
public void shouldReturnNullAfterStream() {
final BigDto bigDto = new BigDto(null);

// we want to receive null state in the end
JsonNullable.ofMissable(bigDto)
// that is why we explicitly allow JsonNullable to produce NULL state in the flow
.flatMap(dto -> JsonNullable.of(dto.getChild()))
.map(ChildOfBigDto::getGrandChild)
.ifPresent(TestCase::assertNull);
}

@Test
public void consumeNotNullValue() {
final String goldenEgg = "goldenEgg";
final ChildOfBigDto child = new ChildOfBigDto("goldenEgg");
final BigDto testedDto = new BigDto(child);

JsonNullable.ofMissable(testedDto)
.map(BigDto::getChild)
.map(ChildOfBigDto::getGrandChild)
.ifNotNull(grandChild -> assertEquals(grandChild, goldenEgg));
}


private static class BigDto {
private ChildOfBigDto child;

public BigDto(ChildOfBigDto child) {
this.child = child;
}

public ChildOfBigDto getChild() {
return this.child;
}
}

private static class ChildOfBigDto {
private String grandChild;

public ChildOfBigDto(String grandChild) {
this.grandChild = grandChild;
}

public String getGrandChild() {
return grandChild;
}
}
}