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

no.digipost.DiggBase Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) Posten Norge AS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package no.digipost;

import no.digipost.function.ThrowingConsumer;
import no.digipost.util.AutoClosed;
import no.digipost.util.ThrowingAutoClosed;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Spliterator.ORDERED;
import static java.util.Spliterators.spliterator;
import static java.util.stream.Collectors.joining;
import static java.util.stream.StreamSupport.stream;

/**
 * Party people, turn up tha...
 *
 * 

–– {@link DiggBase} ––

* *

This class contains basic utilities. Basically.

*/ public final class DiggBase { /** * Not allow {@code null}-references. * * @param description A small description of the reference. Will be used in the exception message if * the reference is {@code null} * @param t the reference * @return the same instance given as argument. * @throws NullPointerException if {@code t} is {@code null}. */ public static T nonNull(String description, T t) { return nonNull(description, d -> t); } /** * Not allow {@code null}-references. * * @param description A small description of the reference. Will be used in the exception message if * the reference is {@code null} * @param t the reference * @param throwIfNull Construct the exception to be thrown if the reference is {@code null}. * @return the same instance given as argument. * @throws X if {@code t} is {@code null}. */ public static T nonNull(String description, T t, Function throwIfNull) throws X { return nonNull(t, () -> throwIfNull.apply(description + " can not be null")); } /** * Not allow {@code null}-references. * * @param t the reference * @param throwIfNull the exception to throw if {@code t} is {@code null} * @return the same instance given as argument. * @throws X if {@code t} is {@code null}. */ public static T nonNull(T t, Supplier throwIfNull) throws X { return nonNull("a reference", s -> t, s -> throwIfNull.get()); } /** * Not allow {@code null}-references. This is a convenience method for when a descriptive refKey * can be used to resolve the reference, for instance to resolve resources * on classpath with {@link Class#getResourceAsStream(String) .class::getResourceAsStream}. * The refKey will appear in the exception message if the resolved reference is {@code null}. * * @param descriptiveRefKey the key used to resolve the reference * @param refResolver the function the will resolve the non-null result based on the description. * @return the reference resolved by {@code refResolver}, never {@code null} */ public static T nonNull(String descriptiveRefKey, Function refResolver) { return nonNull(descriptiveRefKey, refResolver, d -> new NullPointerException("Tried to resolve " + d + ", but got null!")); } /** * Not allow {@code null}-references. * * @param descriptiveRefKey the key used to resolve the reference * @param refResolver the function the will resolve the non-null result based on the description. * @param throwIfNull the function to construct the exception if the {@code refResolver} yields {@code null}. * @return the reference resolved by {@code refResolver}, never {@code null} * @throws X if {@code refResolver} yields {@code null} */ public static T nonNull(String descriptiveRefKey, Function refResolver, Function throwIfNull) throws X { T ref = refResolver.apply(descriptiveRefKey); if (ref != null) { return ref; } else { throw throwIfNull.apply(descriptiveRefKey); } } /** * The "friendly name" of a class is defined as its {@link Class#getSimpleName() simple name}, with * all enclosing classes prepended and joined with a '.' delimiter. This name is typically * useful for logging, naming based on classes, where the fully qualified name would be too verbose * and the simple name is not specific enough. *

* Given the following class model: *

     * class Base {
     *     class Nested {}
     * }
     * 
* The friendly name for the {@code Nested} class is "Base.Nested". * * @param clazz the clazz to get the friendly name of * @return the friendly name */ public static String friendlyName(Class clazz) { Deque> classes = new ArrayDeque<>(); classes.add(clazz); for (Class enclosing = clazz.getEnclosingClass(); enclosing != null; enclosing = enclosing.getEnclosingClass()) { classes.add(enclosing); } return stream(spliterator(classes.descendingIterator(), classes.size(), ORDERED), false) .map(Class::getSimpleName) .collect(joining(".")); } /** * Extract (derive) multiple values from one given object. * * @param object the object to extract values from. * @param extractors each function that will extract a value from the given object. The resulting * value must not be {@code null}. Use {@link #extract(Object, Function...)} * if the extractors may yield non-existing values. * * @return a stream of the extracted values. The resulting stream will have the same size as the amount of * given extractors. * * @param The type of the object to extract from. * @param The resulting most common type of the extracted values. Typically, the extractors * should yield the same type. */ @SafeVarargs @SuppressWarnings({"varargs"}) public static final Stream extract(T object, Function ... extractors) { return Stream.of(extractors).map(e -> e.apply(object)); } /** * Extract (derive) multiple values from one given object. This will only include the "present" * values yielded from the given extractors, and is a shorthand for: *

* {@code {@link #extract(Object, Function...) extract(object, extractors...)}{@link Stream#filter(java.util.function.Predicate) .filter(}{@link Optional#isPresent() Optional::isPresent)}{@link Stream#map(Function) .map(}{@link Optional#get() Optional::get)}} *

* * @param object the object to extract values from. * @param extractors each function that will extract a value from the given object. * * @return a stream of values to be extracted. The resulting stream will have either the same size as * or less than the amount of given extractors. * * * @param The type of the object to extract from. * @param The resulting most common type of the extracted values. Typically, the extractors * should yield the same type. */ @SafeVarargs @SuppressWarnings({"varargs"}) public static final Stream extractIfPresent(T object, Function> ... extractors) { return extract(object, extractors).filter(Optional::isPresent).map(Optional::get); } /** * Create a stream which will yield the exceptions from closing several {@link AutoCloseable closeables}. * Consuming the stream will ensure that all closeables are attempted * {@link AutoCloseable#close() closed}, and any exceptions happening will be available * through the returned stream. *

* To further collapse the possibly multiple exceptions into one throwable exception, * use either * {@link DiggCollectors#toSingleExceptionWithSuppressed() .collect(toSingleExceptionWithSuppressed())} * or {@link DiggCollectors#asSuppressedExceptionsOf(Throwable) .collect(asSuppressedExceptionsOf(..))} * in {@code DiggCollectors}. *

* If you have non-AutoCloseable related actions that need to be performed as well, this can be achieved * by using Stream.concat(close(..), * {@link #forceOnAll(ThrowingConsumer, Object...) forceOnAll(T::action, T ... instances)}) * * * @param closeables The {@code AutoCloseable} instances to close. * * @return the Stream with exceptions, if any, from closing the closeables * * @see DiggCollectors#toSingleExceptionWithSuppressed() * @see DiggCollectors#asSuppressedExceptionsOf(Throwable) */ public static Stream close(AutoCloseable ... closeables) { return forceOnAll(AutoCloseable::close, closeables); } /** * Create a stream which will yield the exceptions (if any) from invoking an {@link ThrowingConsumer action} on * several {@code instances}. Consuming the returned stream will ensure that all instances will have * the action attempted on them, and any exceptions happening will be available through the returned stream. * * @param action the action to execute for each provided instance * @param instances the instances to act on with the provided {@code action}. * * @return the Stream with exceptions, if any */ @SafeVarargs @SuppressWarnings({"varargs"}) public static Stream forceOnAll(ThrowingConsumer action, T ... instances) { return forceOnAll(action, Stream.of(instances)); } /** * Create a stream which will yield the exceptions (if any) from invoking an {@link ThrowingConsumer action} on * several {@code instances}. This also includes exceptions thrown from traversing the given {@link Stream} * of instances, i.e. should resolving an element from the {@code Stream} cause an exception, it will be caught and * included in the returned {@code Stream}. *

* Consuming the returned stream will ensure that all traversed instances will have * the action attempted on them, and any exceptions happening will be available through the returned stream. * * @param action the action to execute for each provided instance * @param instances the instances to act on with the provided {@code action}. * * @return the Stream with exceptions, if any */ public static Stream forceOnAll(ThrowingConsumer action, Stream instances) { return StreamSupport.stream( new FlatMapToExceptionSpliterator<>(action, instances.filter(Objects::nonNull).spliterator()), instances.isParallel()); } private static final class FlatMapToExceptionSpliterator implements Spliterator { private final ThrowingConsumer action; private final Spliterator wrappedSpliterator; private final int characteristics; FlatMapToExceptionSpliterator(ThrowingConsumer action, Spliterator wrappedSpliterator) { this.action = action; this.wrappedSpliterator = wrappedSpliterator; this.characteristics = wrappedSpliterator.characteristics() & ~(SIZED | SUBSIZED | SORTED); } @Override public boolean tryAdvance(Consumer exceptionConsumer) { try { return wrappedSpliterator.tryAdvance(action.ifException(exceptionConsumer::accept)); } catch (Exception e) { exceptionConsumer.accept(e); return true; } } @Override public Spliterator trySplit() { Spliterator triedSplit = wrappedSpliterator.trySplit(); return triedSplit != null ? new FlatMapToExceptionSpliterator<>(action, triedSplit) : null; } @Override public long estimateSize() { return Long.MAX_VALUE; } @Override public int characteristics() { return characteristics; } }; /** * Wrap an arbitrary object to an {@link AutoCloseable} container, and assign an operation to be * performed on the wrapped object when calling {@link AutoCloseable#close()}. This can be * used for legacy classes which does not implement {@code AutoCloseable} to be used with the * {@code try-with-resources} construct. It should not be used (although it can) for * objects already implementing {@code AutoCloseable}. * * @param object the object to be managed with {@code try-with-resources}. * @param closeOperation the operation to invoke on {@code object} to close it. * * @return The wrapper which is {@link AutoCloseable}. Assign this with {@code try-with-resources} to * have it properly closed. * * * @param The type of the wrapped/managed object. * @param The exception which may be throwed when closing by {@link AutoCloseable#close()}. * * @see #autoClose(Object, Consumer) */ public static ThrowingAutoClosed throwingAutoClose(T object, ThrowingConsumer closeOperation) { return new ThrowingAutoClosed(object, closeOperation); } /** * Wrap an arbitrary object to an {@link AutoCloseable} container, and assign an operation to be * performed on the wrapped object when calling {@link AutoCloseable#close()}. This can be * used for legacy classes which does not implement {@code AutoCloseable} to be used with the * {@code try-with-resources} construct. It should not be used (although it can) for * objects already implementing {@code AutoCloseable}. * * @param object the object to be managed with {@code try-with-resources}. * @param closeOperation the operation to invoke on {@code object} to close it. If the operation * can throw a checked exception, use {@link #throwingAutoClose(Object, ThrowingConsumer)} * instead. * * @return The wrapper which is {@link AutoCloseable}. Assign this with {@code try-with-resources} to * have it properly closed. * * * @param The type of the wrapped/managed object. * * @see #throwingAutoClose(Object, ThrowingConsumer) */ public static AutoClosed autoClose(T object, Consumer closeOperation) { return new AutoClosed(object, closeOperation); } private DiggBase() {} }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy