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

org.eclipse.edc.spi.result.AbstractResult Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) 2022 Microsoft Corporation
 *
 *  This program and the accompanying materials are made available under the
 *  terms of the Apache License, Version 2.0 which is available at
 *  https://www.apache.org/licenses/LICENSE-2.0
 *
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Contributors:
 *       Microsoft Corporation - Initial implementation
 *
 */

package org.eclipse.edc.spi.result;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Base result type used by services to indicate success or failure.
 * 

* Service operations should generally never throw checked exceptions. Instead, they should return concrete result types * and raise unchecked exceptions only when an unexpected event happens, such as a programming error. * * @param The type of {@link Failure}. * @param The type of the content. * @param The result self type. */ public abstract class AbstractResult> { private final T content; private final F failure; protected AbstractResult(T content, F failure) { this.content = content; this.failure = failure; } public T getContent() { return content; } public F getFailure() { return failure; } //will cause problems during JSON serialization if failure is null TODO: is this comment still valid? @JsonIgnore public List getFailureMessages() { return failure == null ? List.of() : failure.getMessages(); } public boolean succeeded() { return failure == null; } public boolean failed() { return !succeeded(); } /** * Returns a string that contains all the failure messages. * * @return a string that contains all the failure messages. */ @JsonIgnore // will cause problems during JSON serialization if failure is null TODO: is this comment still valid? public String getFailureDetail() { return failure == null ? null : failure.getFailureDetail(); } /** * Executes a {@link Consumer} if this {@link Result} is successful */ public R onSuccess(Consumer successAction) { if (succeeded()) { successAction.accept(getContent()); } return self(); } /** * Executes a {@link Consumer} if this {@link Result} failed. Passes the {@link Failure} to the consumer */ public R onFailure(Consumer failureAction) { if (failed()) { failureAction.accept(getFailure()); } return self(); } /** * Execute an action if this {@link Result} is not successful. * * @param failureAction The function that maps a {@link Failure} into the content. * @return T the success value if successful, otherwise the object returned by the failureAction */ public T orElse(Function failureAction) { if (failed()) { return failureAction.apply(getFailure()); } else { return getContent(); } } /** * Throws an exception returned by the mapper {@link Function} if this {@link Result} is not successful. * * @param exceptionMapper The function that maps a {@link Failure} into an exception. * @return T the success value */ public T orElseThrow(Function exceptionMapper) throws X { if (failed()) { throw exceptionMapper.apply(getFailure()); } else { return getContent(); } } /** * Return this instance, cast to the {@link R} self type. * * @return this instance. */ @SuppressWarnings({ "unchecked" }) public R self() { return (R) this; } /** * Map the content into another, applying the mapping function. * * @param mapFunction a function that converts the content into another. * @param the new content type. * @param the new result type. * @return a new result with a mapped content if succeeded, a new failed one otherwise. */ public > R2 map(Function mapFunction) { if (succeeded()) { return newInstance(mapFunction.apply(getContent()), null); } else { return newInstance(null, getFailure()); } } /** * Maps this {@link Result} into another. If this {@link Result} is successful, the content is discarded. If this * {@link Result} failed, the failures are carried over. */ public > R2 mapEmpty() { return map(it -> null); } /** * Maps this {@link Result} into another. The content gets discarded, this method can be used to forward failures * to the caller. */ public > R2 mapFailure() { return map(it -> null); } /** * Maps one result into another, applying the mapping function. * * @param mappingFunction a function converting this result into another * @return the result of the mapping function */ public > R2 flatMap(Function mappingFunction) { return mappingFunction.apply(self()); } /** * If the result is successful maps the content into a result applying the mapping function, otherwise do nothing. * * @param mappingFunction a function converting this result into another * @return the result of the mapping function */ public > R2 compose(Function mappingFunction) { if (succeeded()) { return mappingFunction.apply(getContent()); } else { return newInstance(null, getFailure()); } } /** * If the result is failed maps the content into a result applying the mapping function, otherwise do nothing. * * @param mappingFunction a function converting this result into another when it's failed. * @return the result of the mapping function */ public R recover(Function mappingFunction) { if (succeeded()) { return newInstance(getContent(), null); } else { return mappingFunction.apply(getFailure()); } } /** * Returns a new result instance. * This default implementation exists only to avoid breaking changes, in a future this should become an abstract * method. * * @param content the content. * @param failure the failure. * @param the new result type. * @param the new content type. * @return a new result instance */ @NotNull protected abstract , C1> R1 newInstance(@Nullable C1 content, @Nullable F failure); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy