/* * Copyright 2012-2017 the original author or authors. * * 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 org.springframework.boot.context.properties.bind; import java.util.NoSuchElementException; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import org.springframework.beans.BeanUtils; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** * A container object to return result of a {@link Binder} bind operation. May contain * either a successfully bound object or an empty result. * * @param <T> The result type * @author Phillip Webb * @author Madhura Bhave * @since 2.0.0 */ public final class BindResult<T> { private static final BindResult<?> UNBOUND = new BindResult<>(null); private final T value; private BindResult(T value) { this.value = value; } /** * Return the object that was bound or throw a {@link NoSuchElementException} if no * value was bound. * @return the the bound value (never {@code null}) * @throws NoSuchElementException if no value was bound * @see #isBound() */ public T get() throws NoSuchElementException { if (this.value == null) { throw new NoSuchElementException("No value bound"); } return this.value; } /** * Returns {@code true} if a result was bound. * @return if a result was bound */ public boolean isBound() { return (this.value != null); } /** * Invoke the specified consumer with the bound value, or do nothing if no value has * been bound. * @param consumer block to execute if a value has been bound */ public void ifBound(Consumer<? super T> consumer) { Assert.notNull(consumer, "Consumer must not be null"); if (this.value != null) { consumer.accept(this.value); } } /** * Apply the provided mapping function to the bound value, or return an updated * unbound result if no value has been bound. * @param <U> The type of the result of the mapping function * @param mapper a mapping function to apply to the bound value. The mapper will not * be invoked if no value has been bound. * @return an {@code BindResult} describing the result of applying a mapping function * to the value of this {@code BindResult}. */ public <U> BindResult<U> map(Function<? super T, ? extends U> mapper) { Assert.notNull(mapper, "Mapper must not be null"); return of(this.value == null ? null : mapper.apply(this.value)); } /** * Return the object that was bound, or {@code other} if no value has been bound. * @param other the value to be returned if there is no bound value (may be * {@code null}) * @return the value, if bound, otherwise {@code other} */ public T orElse(T other) { return (this.value != null ? this.value : other); } /** * Return the object that was bound, or the result of invoking {@code other} if no * value has been bound. * @param other a {@link Supplier} of the value to be returned if there is no bound * value * @return the value, if bound, otherwise the supplied {@code other} */ public T orElseGet(Supplier<? extends T> other) { return (this.value != null ? this.value : other.get()); } /** * Return the object that was bound, or a new instance of the specified class if no * value has been bound. * @param type the type to create if no value was bound * @return the value, if bound, otherwise a new instance of {@code type} */ public T orElseCreate(Class<? extends T> type) { Assert.notNull(type, "Type must not be null"); return (this.value != null ? this.value : BeanUtils.instantiateClass(type)); } /** * Return the object that was bound, or throw an exception to be created by the * provided supplier if no value has been bound. * @param <X> 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 */ public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (this.value == null) { throw exceptionSupplier.get(); } return this.value; } @Override public int hashCode() { return ObjectUtils.nullSafeHashCode(this.value); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } return ObjectUtils.nullSafeEquals(this.value, ((BindResult<?>) obj).value); } @SuppressWarnings("unchecked") static <T> BindResult<T> of(T value) { if (value == null) { return (BindResult<T>) UNBOUND; } return new BindResult<>(value); } }