All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adgear.anoa.Anoa Maven / Gradle / Ivy

Go to download

Core classes for Anoa library, which aims to be a safe, convenient and fast record de/serialization wrapper for the Avro, Thrift and Jackson libraries, using the functional idioms of Java 8. The anoa-core module tries to keep upstream dependencies to a minimum.

There is a newer version: 3.1.2
Show newest version
package com.adgear.anoa;

import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * A container object which may or may not contain a non-null value, much like {@link Optional}: if
 * a value is present, {@code isPresent()} will return {@code true} and {@code get()} will return
 * the value.
 *
 * In addition to the functionalities offered by {@link Optional}, these objects can be decorated by
 * metadata. Possible uses include documenting the presence or absence of value, documenting the
 * value itself, or documenting any exceptions handled during the transformation of the value. For
 * the latter use case, consider using the factory class {@code AnoaHandler}.
 *
 * 

This is a * * value-based class; use of identity-sensitive operations (including reference equality * ({@code ==}), identity hash code, or synchronization) on instances of {@code Anoa} may have * unpredictable results and should be avoided. * * @param Value type * @param Metadata type * @see Optional * @see AnoaHandler */ final public class Anoa { static final Anoa EMPTY = new Anoa<>(null, new Object[0]); final T value; final M[] meta; private Anoa(T value, M[] meta) { this.value = value; this.meta = meta; } /** * Factory method * * @see Optional#empty() */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa empty() { return EMPTY; } /** * Factory method * * @throws NullPointerException when metadata stream is null * @see Optional#empty() */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa empty( /*@NonNull*/ Stream metadata) { Objects.requireNonNull(metadata); return ofNullable(null, metadata); } /** * Factory method * * @throws NullPointerException when value is null * @see Optional#of(Object) */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa of( /*@NonNull*/ T value) { Objects.requireNonNull(value); return ofNullable(value); } /** * Factory method * * @throws NullPointerException when value or metadata stream is null * @see Optional#of(Object) */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa of( /*@NonNull*/ T value, /*@NonNull*/ Stream metadata) { Objects.requireNonNull(value); Objects.requireNonNull(metadata); return ofNullable(value, metadata); } /** * Factory method * * @see Optional#ofNullable(Object) */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa ofNullable( /*@Nullable*/ T value) { return new Anoa<>(value, (M[]) EMPTY.meta); } /** * Factory method * * @throws NullPointerException when metadata stream is null * @see Optional#ofNullable(Object) */ @SuppressWarnings("unchecked") static public /*@NonNull*/ Anoa ofNullable( /*@Nullable*/ T value, /*@NonNull*/ Stream metadata) { Objects.requireNonNull(metadata); return new Anoa<>(value, (M[]) metadata.toArray()); } /** * Returns a stream of metadata elements decorating this {@code Anoa} */ public /*@NonNull*/ Stream meta() { return Arrays.stream(meta); } /** * Returns the value held in this {@code Anoa} */ public Optional asOptional() { return Optional.ofNullable(value); } /** * Returns the value held in this {@code Anoa} in a stream, if exists */ public Stream asStream() { return (value != null) ? Stream.of(value) : Stream.empty(); } /** * If a value is present in this {@code Anoa}, returns the value, otherwise throws {@link * NoSuchElementException}. * * @see Anoa#isPresent() * @see Optional#get() */ public T get() { if (value == null) { throw new NoSuchElementException(); } return value; } /** * Return {@code true} if there is a value present, otherwise {@code false}. * * @see Optional#isPresent() */ public boolean isPresent() { return (value != null); } /** * If a value is present, invoke the specified consumer with the value, otherwise do nothing. * * @param consumer lambda to be invoked with the value, if present * @throws NullPointerException if value is present and {@code consumer} is null * @see Optional#ifPresent(Consumer) */ public void ifPresent(Consumer consumer) { if (value != null) { consumer.accept(value); } } /** * If a value is present, and the value matches the given predicate, return an {@code * Anoa} describing the value, otherwise return a valueless {@code Anoa}. * * @param predicate a predicate to apply to the value, if present * @return an {@code Anoa} describing the value of this {@code Anoa} if a value is * present and the value matches the given predicate, otherwise a valueless {@code Anoa} * @throws NullPointerException if the predicate is null * @see Optional#filter(Predicate) */ public Anoa filter(Predicate predicate) { if (value == null) { return this; } else { return predicate.test(value) ? this : new Anoa<>(null, meta); } } /** * If a value is present, apply the provided mapping function to it, return that result wrapped * in an {@code Anoa}, otherwise return a valueless {@code Anoa}. * * @param The type parameter to the {@code Anoa} returned by * @param mapper a mapping function to apply to the value, if present * @return the result of applying an {@code Anoa}-bearing mapping function to the value of * this {@code Anoa}, if a value is present, otherwise a valueless {@code Anoa} * @throws NullPointerException if the mapping function is null or returns a null result * @see Optional#map(Function) */ @SuppressWarnings("unchecked") public Anoa map(Function mapper) { if (value == null) { return (Anoa) this; } else { final U result = mapper.apply(value); Objects.requireNonNull(result); return new Anoa<>(result, meta); } } /** * If a value is present, apply the provided {@code Anoa}-bearing mapping function to it, * return that result, otherwise return a valueless {@code Anoa}. * * @param The type parameter to the {@code Anoa} returned by * @param mapper a mapping function to apply to the value, if present * @return the result of applying an {@code Anoa}-bearing mapping function to the value of * this {@code Anoa}, if a value is present, otherwise a valueless {@code Anoa} * @throws NullPointerException if the mapping function is null or returns a null result * @see Optional#flatMap(Function) */ @SuppressWarnings("unchecked") public Anoa flatMap(Function> mapper) { if (value == null) { return (Anoa) this; } else { final Anoa result = mapper.apply(value); Objects.requireNonNull(result); final M[] newMeta = Arrays.copyOf(meta, meta.length + result.meta.length); System.arraycopy(result.meta, 0, newMeta, meta.length, result.meta.length); return new Anoa<>(result.value, newMeta); } } /** * Return the value if present, otherwise return {@code other} * * @param other the value to be returned if there is no value present, may be null * @return the value, if present, otherwise {@code other} * @see Optional#orElse(Object) */ public T orElse(/*@Nullable*/ T other) { return (value != null) ? value : other; } /** * Return the value if present, otherwise invoke {@code other} and return the result of that * invocation. * * @param other a {@code Supplier} whose result is returned if no value is present * @return the value if present otherwise the result of {@code other.get()} * @throws NullPointerException if value is not present and {@code other} is null * @see Optional#orElseGet(Supplier) */ public T orElseGet(/*@NonNull*/ Supplier other) { return (value != null) ? value : other.get(); } /** * Return the contained value, if present, otherwise throw an exception to be created by the * provided supplier. * * @param Type of the exception to be thrown * @param exceptionSupplier The supplier which will return the exception to be thrown * @return the present value * @throws X if there is no value present * @throws NullPointerException if no value is present and {@code exceptionSupplier} is null * @see Optional#orElseThrow(Supplier) */ public T orElseThrow(Supplier exceptionSupplier) throws X { if (value == null) { throw exceptionSupplier.get(); } return value; } /** * Indicates whether some other object is "equal to" this Anoa. The other object is considered * equal if it is also an {@code Anoa} and: *

    *
  • both instances have no value present, or both instances have values which are "equal to" * each other via {@code equals()}, and; *
  • both instances have no metadata present, or both instances have metadata which is "equal * to" each other via {@code equals()}. *
* * @param obj an object to be tested for equality * @return {@code true} if the other object is "equal to" this object, otherwise {@code false} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || !(obj instanceof Anoa)) { return false; } final Anoa anoa = (Anoa) obj; return Objects.equals(value, anoa.value) && Arrays.equals(meta, anoa.meta); } /** * Returns a hash code generated solely from the value and the metadata, if present. */ @Override public int hashCode() { return Objects.hash(value, meta); } /** * Returns a non-empty string representation of this Anoa suitable for debugging. The exact * presentation format is unspecified and may vary between implementations and versions. * * @implSpec If a value is present the result must include its string representation in the * result; same for metadata. Objects must be unambiguously differentiable. */ @Override public String toString() { StringBuilder sb = new StringBuilder().append("Anoa<").append(value); char c = '|'; for (Object m : meta) { sb.append(c).append(m); c = ','; } return sb.append('>').toString(); } }