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

ru.progrm_jarvis.javacommons.object.extension.LegacyOptionalExtensions Maven / Gradle / Ivy

package ru.progrm_jarvis.javacommons.object.extension;

import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.val;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static java.lang.invoke.MethodType.methodType;

/**
 * Extensions to provide new {@link Optional} methods on older Java versions.
 */
@UtilityClass
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") // this is the whole concept of this class
public class LegacyOptionalExtensions {

    /**
     * Method handle of
     * {@link Optional}{@code .isEmpty()} method
     * being {@code null} if this method is unavailable.
     */
    private final @Nullable MethodHandle IS_EMPTY_METHOD_HANDLE;

    /**
     * Method handle of
     * {@link Optional}{@code .ifPresentOrElse(}{@link Consumer}{@code , }{@link Runnable}{@code )} method
     * being {@code null} if this method is unavailable.
     */
    private final @Nullable MethodHandle IF_PRESENT_OR_ELSE_METHOD_HANDLE;

    /**
     * Method handle of
     * {@link Optional}{@code .or(}{@link Supplier}{@code >)} method
     * being {@code null} if this method is unavailable.
     */
    private final @Nullable MethodHandle OR_METHOD_HANDLE;

    /**
     * Method handle of
     * {@link Optional}{@code .stream()} method
     * being {@code null} if this method is unavailable.
     */
    private final @Nullable MethodHandle STREAM_METHOD_HANDLE;

    /**
     * Method handle of
     * {@link Optional}{@code .orElseThrow()} method
     * being {@code null} if this method is unavailable.
     */
    private final @Nullable MethodHandle OR_ELSE_THROW_METHOD_HANDLE;

    static {
        val lookup = MethodHandles.lookup();
        {
            MethodHandle handle;
            try {
                handle = lookup.findVirtual(
                        Optional.class, "isEmpty", methodType(boolean.class)
                );
            } catch (final NoSuchMethodException | IllegalAccessException e) {
                handle = null;
            }
            IS_EMPTY_METHOD_HANDLE = handle;
        }
        {
            MethodHandle handle;
            try {
                handle = lookup.findVirtual(
                        Optional.class, "ifPresentOrElse", methodType(void.class, Consumer.class, Runnable.class)
                );
            } catch (final NoSuchMethodException | IllegalAccessException e) {
                handle = null;
            }
            IF_PRESENT_OR_ELSE_METHOD_HANDLE = handle;
        }
        {
            MethodHandle handle;
            try {
                handle = lookup.findVirtual(
                        Optional.class, "or", methodType(Optional.class, Supplier.class)
                );
            } catch (final NoSuchMethodException | IllegalAccessException e) {
                handle = null;
            }
            OR_METHOD_HANDLE = handle;
        }
        {
            MethodHandle handle;
            try {
                handle = lookup.findVirtual(
                        Optional.class, "stream", methodType(Stream.class)
                );
            } catch (final NoSuchMethodException | IllegalAccessException e) {
                handle = null;
            }
            STREAM_METHOD_HANDLE = handle;
        }
        {
            MethodHandle handle;
            try {
                handle = lookup.findVirtual(
                        Optional.class, "orElseThrow", methodType(Object.class)
                );
            } catch (final NoSuchMethodException | IllegalAccessException e) {
                handle = null;
            }
            OR_ELSE_THROW_METHOD_HANDLE = handle;
        }
    }

    /**
     * Checks if the given optional is {@link Optional#empty() empty}.
     *
     * @param optional optional on which the operation happens
     * @param  type of the value
     * @return {@code true} if the optional is {@link Optional#empty()} and {@code false} otherwise
     * @apiNote this method is available on {@link Optional} itself since Java 11
     */
    @SneakyThrows // call to `MethodHandle#invokeExact(...)`
    public  boolean isEmpty(final @NotNull Optional optional) {
        return IS_EMPTY_METHOD_HANDLE == null
                ? !optional.isPresent() : (boolean) IS_EMPTY_METHOD_HANDLE.invokeExact(optional);
    }

    /**
     * Runs the corresponding action depending on whether the optional is {@link Optional#isPresent() present}.
     *
     * @param optional optional on which the operation happens
     * @param action action to be run on non-{@link Optional#empty() empty} optional's value
     * @param emptyAction action to be run if the optional is empty
     * @param  type of the value
     * @throws NullPointerException if the optional is {@link Optional#isPresent() present} but {@code action} is {@code
     * null}
     * or if the optional is {@link Optional#empty() empty} but {@code emptyAction} is {@code null}
     * @apiNote this method is available on {@link Optional} itself since Java 9
     */
    @SneakyThrows // call to `MethodHandle#invokeExact(...)`
    public  void ifPresentOrElse(final @NotNull Optional optional,
                                    // note: nullness checking of lambdas is done lazily according to the contract
                                    final @NotNull Consumer action,
                                    final @NotNull Runnable emptyAction) {
        if (IF_PRESENT_OR_ELSE_METHOD_HANDLE == null) if (optional.isPresent()) action.accept(optional.get());
        else emptyAction.run();
        else IF_PRESENT_OR_ELSE_METHOD_HANDLE.invokeExact(optional, action, emptyAction);
    }

    /**
     * Returns the given optional if it is {@link Optional#isPresent() present}
     * or an optional provided by the given supplier otherwise.
     *
     * @param optional optional on which the operation happens
     * @param supplier supplier of the value in case of optional being {@link Optional#empty()}
     * @param  type of the value
     * @return given optional if it is {@link Optional#isPresent() present}
     * or an optional provided by the given supplier otherwise
     *
     * @throws NullPointerException if {@code supplier} is {@code null} or the value provided by it is {@code null}
     * @apiNote this method is available on {@link Optional} itself since Java 9
     */
    @Contract("_, null -> fail")
    @SneakyThrows // call to `MethodHandle#invokeExact(...)`
    @SuppressWarnings({"unchecked" /* return casts */, "Contract" /* // Lombok's annotation is treated incorrectly */})
    public  @NotNull Optional or(@NotNull Optional optional, // variable may be reused for the other value
                                       final @NonNull Supplier<@NonNull ? extends Optional> supplier) {
        if (OR_METHOD_HANDLE == null) {
            //noinspection OptionalAssignedToNull: this check is required by contract
            if (!optional.isPresent() && (optional = (Optional) supplier.get())
                    == null) throw new NullPointerException("supplier provided a null Optional");

            return optional;
        }

        return (Optional) OR_METHOD_HANDLE.invokeExact(optional, supplier);
    }

    /**
     * Returns the {@link Stream stream} created from the optional's value if it is {@link Optional#isPresent() present}
     * or an {@link Stream#empty() empty stream} otherwise.
     *
     * @param optional optional on which the operation happens
     * @param  type of the value
     * @return given optional if it is {@link Optional#isPresent() present}
     * or an optional provided by the given supplier otherwise
     */
    @SuppressWarnings("unchecked") // return cast
    @SneakyThrows // call to `MethodHandle#invokeExact(...)`
    public  Stream stream(final @NotNull Optional optional) {
        return STREAM_METHOD_HANDLE == null
                ? optional.map(Stream::of).orElseGet(Stream::empty)
                : (Stream) STREAM_METHOD_HANDLE.invokeExact(optional);
    }

    /**
     * Returns the value of the optional if it is {@link Optional#isPresent() present}
     * or throws {@link NoSuchElementException} otherwise.
     *
     * @param optional optional on which the operation happens
     * @param  type of the value
     * @return the value of the optional if it is {@link Optional#isPresent() present}
     */
    @SuppressWarnings("unchecked") // return cast
    @SneakyThrows // call to `MethodHandle#invokeExact(...)`
    public  T orElseThrow(final @NotNull Optional optional) {
        return OR_ELSE_THROW_METHOD_HANDLE == null
                ? optional.orElseThrow(() -> new NoSuchElementException("No value present"))
                : (T) OR_ELSE_THROW_METHOD_HANDLE.invokeExact(optional);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy