diff --git a/geode-spring-boot-starter/src/main/java/org/springframework/boot/data/geode/core/util/ObjectUtils.java b/geode-spring-boot-starter/src/main/java/org/springframework/boot/data/geode/core/util/ObjectUtils.java new file mode 100644 index 00000000..aabe805c --- /dev/null +++ b/geode-spring-boot-starter/src/main/java/org/springframework/boot/data/geode/core/util/ObjectUtils.java @@ -0,0 +1,124 @@ +/* + * Copyright 2018 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.data.geode.core.util; + +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.lang.Nullable; + +/** + * The ObjectUtils class... + * + * @author John Blum + * @since 1.0.0 + */ +@SuppressWarnings("all") +public abstract class ObjectUtils extends org.springframework.util.ObjectUtils { + + private static final Logger logger = LoggerFactory.getLogger(ObjectUtils.class); + + /** + * Executes the given {@link ExceptionThrowingOperation} handling any checked {@link Exception} thrown during + * the normal execution of the operation by rethrowing an {@link IllegalStateException} wrapping + * the checked {@link Exception}. + * + * @param {@link Class type} of the operation result. + * @param operation {@link ExceptionThrowingOperation} to execute. + * @return the result of the given {@link ExceptionThrowingOperation} or throw an {@link IllegalStateException} + * wrapping the checked {@link Exception} thrown by the operation. + * @see org.springframework.boot.data.geode.core.util.ObjectUtils.ExceptionThrowingOperation + * @see #doOperationSafely(ExceptionThrowingOperation, Object) + */ + @Nullable + public static T doOperationSafely(ExceptionThrowingOperation operation) { + return doOperationSafely(operation, null); + } + + /** + * Executes the given {@link ExceptionThrowingOperation} handling any checked {@link Exception} thrown + * during the normal execution of the operation, returning the {@link Object default value} in its place + * or throwing a {@link RuntimeException} if the {@link Object default value} is {@literal null}. + * + * @param {@link Class type} of the operation result as well as the {@link Object default value}. + * @param operation {@link ExceptionThrowingOperation} to execute. + * @param defaultValue {@link Object value} to return if the operation results in a checked {@link Exception}. + * @return the result of the given {@link ExceptionThrowingOperation}, returning the {@link Object default value} + * if the operation throws a checked {@link Exception} or throws an {@link IllegalStateException} wrapping + * the checked {@link Exception} if the {@link Object default value} is {@literal null}. + * @throws IllegalStateException if the {@link ExceptionThrowingOperation} throws a checked {@link Exception} + * and {@link Object default value} is {@literal null}. + * @see org.springframework.boot.data.geode.core.util.ObjectUtils.ExceptionThrowingOperation + * @see #returnValueThrowOnNull(Object, RuntimeException) + */ + @Nullable + public static T doOperationSafely(ExceptionThrowingOperation operation, T defaultValue) { + + try { + return operation.doExceptionThrowingOperation(); + } + catch (Exception cause) { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Failed to execute operation [%s]", operation), cause); + } + + return returnValueThrowOnNull(defaultValue, + newIllegalStateException(cause, "Failed to execute operation")); + } + } + + /** + * Returns the given {@link Object value} or throws an {@lin IllegalArgumentException} + * if {@link Object value} is {@literal null}. + * + * @param {@link Class type} of the {@link Object value}. + * @param value {@link Object} to return. + * @return the {@link Object value} or throw an {@link IllegalArgumentException} + * if {@link Object value} is {@literal null}. + * @see #returnValueThrowOnNull(Object, RuntimeException) + */ + public static T returnValueThrowOnNull(T value) { + return returnValueThrowOnNull(value, newIllegalArgumentException("Value must not be null")); + } + + /** + * Returns the given {@link Object value} or throws the given {@lin RunimeException} + * if {@link Object value} is {@literal null}. + * + * @param {@link Class type} of the {@link Object value}. + * @param value {@link Object} to return. + * @param exception {@link RuntimeException} to throw if {@link Object value} is {@literal null}. + * @return the {@link Object value} or throw the given {@link RuntimeException} + * if {@link Object value} is {@literal null}. + */ + public static T returnValueThrowOnNull(T value, RuntimeException exception) { + + if (value == null) { + throw exception; + } + + return value; + } + + @FunctionalInterface + public interface ExceptionThrowingOperation { + T doExceptionThrowingOperation() throws Exception; + } +} diff --git a/geode-spring-boot-starter/src/test/java/org/springframework/boot/data/geode/core/util/ObjectUtilsUnitTests.java b/geode-spring-boot-starter/src/test/java/org/springframework/boot/data/geode/core/util/ObjectUtilsUnitTests.java new file mode 100644 index 00000000..da3fb592 --- /dev/null +++ b/geode-spring-boot-starter/src/test/java/org/springframework/boot/data/geode/core/util/ObjectUtilsUnitTests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 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.data.geode.core.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException; + +import org.junit.Test; + +/** + * Unit tests for {@link ObjectUtils}. + * + * @author John Blum + * @see org.junit.Test + * @since 1.0.0 + */ +public class ObjectUtilsUnitTests { + + @Test + public void doOperationSafelyReturnsResult() { + assertThat(ObjectUtils.doOperationSafely(() -> "test")).isEqualTo("test"); + } + + @Test + public void doOperationSafelyReturnsDefaultValue() { + assertThat(ObjectUtils.doOperationSafely(() -> { throw newRuntimeException("test"); }, + "default value")).isEqualTo("default value"); + } + + @Test(expected = IllegalStateException.class) + public void doOperationSafelyThrowsIllegalStateException() { + + try { + ObjectUtils.doOperationSafely(() -> { throw newRuntimeException("test"); }, null); + } + catch (IllegalStateException expected) { + + assertThat(expected).hasMessage("Failed to execute operation"); + assertThat(expected).hasCauseInstanceOf(RuntimeException.class); + assertThat(expected.getCause()).hasMessage("test"); + assertThat(expected.getCause()).hasNoCause(); + + throw expected; + } + } + + @Test + public void returnValueThrowOnNullWithNonNullValueReturnsValue() { + assertThat(ObjectUtils.returnValueThrowOnNull("test")).isEqualTo("test"); + } + + @Test(expected = RuntimeException.class) + public void returnValueThrowOnNullWithNullValueThrowsException() { + + try { + ObjectUtils.returnValueThrowOnNull(null, newRuntimeException("test")); + } + catch (RuntimeException expected) { + + assertThat(expected).hasMessage("test"); + assertThat(expected).hasNoCause(); + + throw expected; + } + } +}