Add null-safe asType(:Object, :Class) method to cast the given source Object into an instance of the given Class type.
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.geode.core.util;
|
||||
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
@@ -29,19 +28,25 @@ import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ObjectUtils} class is an abstract utility class with operations for {@link Object objects}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.Object
|
||||
* @see java.lang.reflect.Constructor
|
||||
* @see java.lang.reflect.Field
|
||||
* @see java.lang.reflect.Method
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@@ -49,6 +54,37 @@ public abstract class ObjectUtils extends org.springframework.util.ObjectUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ObjectUtils.class);
|
||||
|
||||
/**
|
||||
* Tries to cast the given source {@link Object} into an instance of the given {@link Class} type.
|
||||
*
|
||||
* This method is cable of handling GemFire/Geode {@link PdxInstance} types.
|
||||
*
|
||||
* @param <T> desired {@link Class type} of the source {@link Object}.
|
||||
* @param source {@link Object} to evaluate.
|
||||
* @param type desired target {@link Class} type; must not be {@literal null}.
|
||||
* @return the source {@link Object} cast to an instance of the given {@link Class} type.
|
||||
* @throws IllegalArgumentException if the source {@link Object} is not an instance of
|
||||
* the given {@link Class} type or the {@link Class} type is {@literal null}.
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see java.lang.Class
|
||||
* @see java.lang.Object
|
||||
*/
|
||||
public static @Nullable <T> T asType(@Nullable Object source, @NonNull Class<T> type) {
|
||||
|
||||
Assert.notNull(type, "Class type must not be null");
|
||||
|
||||
Object target = source instanceof PdxInstance
|
||||
? ((PdxInstance) source).getObject()
|
||||
: source;
|
||||
|
||||
return target == null ? null
|
||||
: Optional.of(target)
|
||||
.filter(type::isInstance)
|
||||
.map(type::cast)
|
||||
.orElseThrow(() -> newIllegalArgumentException("Object [%s] is not an instance of type [%s]",
|
||||
nullSafeClassName(target), type.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link ExceptionThrowingOperation} handling any checked {@link Exception} thrown during
|
||||
* the normal execution of the operation by rethrowing an {@link IllegalStateException} wrapping
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
* or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.geode.core.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -25,16 +28,129 @@ import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.pdx.PdxInstance;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ObjectUtils}.
|
||||
* Unit Tests for {@link ObjectUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.reflect.Field
|
||||
* @see java.lang.reflect.Method
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.pdx.PdxInstance
|
||||
* @see org.springframework.geode.core.util.ObjectUtils
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ObjectUtilsUnitTests {
|
||||
|
||||
@Test
|
||||
public void asMatchingBaseType() {
|
||||
|
||||
B object = new B();
|
||||
A value = ObjectUtils.asType(object, A.class);
|
||||
|
||||
assertThat(value).isNotNull();
|
||||
assertThat(value).isSameAs(object);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asMatchingSubType() {
|
||||
|
||||
A object = new B();
|
||||
B value = ObjectUtils.asType(object, B.class);
|
||||
|
||||
assertThat(value).isNotNull();
|
||||
assertThat(value).isSameAs(object);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void asNonMatchingType() {
|
||||
|
||||
Object object = new B();
|
||||
|
||||
try {
|
||||
ObjectUtils.asType(object, C.class);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Object [%s] is not an instance of type [%s]",
|
||||
object.getClass().getName(), C.class.getName());
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asPdxInstanceType() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(new B()).when(mockPdxInstance).getObject();
|
||||
|
||||
assertThat(ObjectUtils.asType(mockPdxInstance, B.class)).isInstanceOf(B.class);
|
||||
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void asPdxInstanceTypeReturnNonMatchingType() {
|
||||
|
||||
C source = new C();
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(source).when(mockPdxInstance).getObject();
|
||||
|
||||
try {
|
||||
ObjectUtils.asType(mockPdxInstance, A.class);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Object [%s] is not an instance of type [%s]",
|
||||
source.getClass().getName(), A.class.getName());
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asPdxInstanceTypeReturningNull() {
|
||||
|
||||
PdxInstance mockPdxInstance = mock(PdxInstance.class);
|
||||
|
||||
doReturn(null).when(mockPdxInstance).getObject();
|
||||
|
||||
assertThat(ObjectUtils.asType(mockPdxInstance, A.class)).isNull();
|
||||
|
||||
verify(mockPdxInstance, times(1)).getObject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asTypeWithNullSource() {
|
||||
assertThat(ObjectUtils.asType(null, A.class)).isNull();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void asTypeWithNullType() {
|
||||
|
||||
try {
|
||||
ObjectUtils.asType(new A(), null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("Class type must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doOperationSafelyReturnsResult() {
|
||||
assertThat(ObjectUtils.doOperationSafely(() -> "test")).isEqualTo("test");
|
||||
@@ -135,7 +251,7 @@ public class ObjectUtilsUnitTests {
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getFieldWithNullFieldThrowsIllegalArgumentException() throws Exception {
|
||||
public void getFieldWithNullFieldThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
ObjectUtils.get(new TestObject(), (Field) null);
|
||||
@@ -265,4 +381,11 @@ public class ObjectUtilsUnitTests {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
|
||||
static class A { }
|
||||
|
||||
static class B extends A { }
|
||||
|
||||
static class C { }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user