This repository has been archived by the owner on May 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
248 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
...core/src/main/java/uk/gov/justice/services/test/utils/core/reflection/ReflectionUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package uk.gov.justice.services.test.utils.core.reflection; | ||
|
||
|
||
import static java.util.Arrays.stream; | ||
import static java.util.Comparator.comparing; | ||
import static java.util.stream.Collectors.toList; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import edu.umd.cs.findbugs.annotations.SuppressWarnings; | ||
|
||
public final class ReflectionUtil { | ||
|
||
private ReflectionUtil() { | ||
} | ||
|
||
/** | ||
* @param classWithMethods - class type | ||
* @return - list of methods of the classWithMethods | ||
*/ | ||
public static List<Method> methodsOf(final Class<?> classWithMethods) { | ||
return stream(classWithMethods.getDeclaredMethods()).filter(m -> !m.getName().contains("jacoco") && !m.getName().contains("lambda")) | ||
.sorted(comparing(Method::getName)) | ||
.collect(toList()); | ||
} | ||
|
||
/** | ||
* returns first method of the given class | ||
* | ||
* @param classWithMethod - class type | ||
* @return - first method of the given classWithMethod | ||
*/ | ||
public static Optional<Method> firstMethodOf(final Class<?> classWithMethod) { | ||
final List<Method> methods = methodsOf(classWithMethod); | ||
|
||
return methods.stream().findFirst(); | ||
} | ||
|
||
/** | ||
* Returns method of the given class with the given name | ||
* | ||
* @param classWithMethod - class type | ||
* @param methodName - name of method in class | ||
* @return - method of the given class with the given name | ||
*/ | ||
public static Optional<Method> methodOf(final Class<?> classWithMethod, final String methodName) { | ||
return methodsOf(classWithMethod).stream() | ||
.filter(method -> method.getName().equals(methodName)) | ||
.findFirst(); | ||
} | ||
|
||
/** | ||
* Get the method of a Class with the given annotation. Returns Optional.empty() if no method | ||
* found. | ||
* | ||
* @param classWithMethod - the Class with the annotated method | ||
* @param annotationClass - the Annotation Class to find | ||
* @return the Method with the given annotation | ||
*/ | ||
public static Optional<Method> annotatedMethod(final Class<?> classWithMethod, final Class<? extends Annotation> annotationClass) { | ||
return stream(classWithMethod.getDeclaredMethods()) | ||
.filter(method -> method.isAnnotationPresent(annotationClass)) | ||
.findFirst(); | ||
} | ||
|
||
/** | ||
* sets value of the field by reflection | ||
* | ||
* @param object - object to modify | ||
* @param fieldName - name of the field belonging to the object | ||
* @param fieldValue - value of the field to be set | ||
* @throws IllegalAccessException if unable to access field | ||
*/ | ||
public static void setField(final Object object, final String fieldName, final Object fieldValue) | ||
throws IllegalAccessException { | ||
final Optional<Field> field = fieldOf(object.getClass(), fieldName); | ||
|
||
if (field.isPresent()) { | ||
field.get().setAccessible(true); | ||
field.get().set(object, fieldValue); | ||
} | ||
} | ||
|
||
/** | ||
* Searches for a field in the given class by reflection | ||
* | ||
* @param classWithField - class type | ||
* @param fieldName - name of field in class | ||
* @return - field belonging to the given classWithField with the given fieldName | ||
*/ | ||
public static Optional<Field> fieldOf(final Class<?> classWithField, final String fieldName) { | ||
return stream(classWithField.getDeclaredFields()) | ||
.filter(f -> f.getName().equals(fieldName)) | ||
.findFirst(); | ||
} | ||
|
||
/** | ||
* Get the value of a field from an Object | ||
* | ||
* @param object - object to find value from | ||
* @param fieldName - name of field in class | ||
* @param returnClassType - defines the return field value class type | ||
* @param <T> the class type to return | ||
* @return the field value returned cast to the class type defined by the returnClassType | ||
*/ | ||
public static <T> Optional<T> fieldValue(final Object object, | ||
final String fieldName, | ||
@SuppressWarnings("unused") final Class<T> returnClassType) throws IllegalAccessException { | ||
return fieldValue(object, fieldName) | ||
.map(o -> (T) o); | ||
} | ||
|
||
/** | ||
* Get the value of a field from an Object | ||
* | ||
* @param object - object to find value from | ||
* @param fieldName - name of field in class | ||
* @return - field belonging to the given clazz with the given fieldName | ||
*/ | ||
public static Optional<Object> fieldValue(final Object object, final String fieldName) throws IllegalAccessException { | ||
final Optional<Field> field = fieldOf(object.getClass(), fieldName); | ||
|
||
if (field.isPresent()) { | ||
field.get().setAccessible(true); | ||
|
||
return Optional.ofNullable(field.get().get(object)); | ||
} | ||
|
||
return Optional.empty(); | ||
} | ||
} |
111 changes: 111 additions & 0 deletions
111
.../src/test/java/uk/gov/justice/services/test/utils/core/reflection/ReflectionUtilTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package uk.gov.justice.services.test.utils.core.reflection; | ||
|
||
import static java.lang.annotation.ElementType.METHOD; | ||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
import static net.trajano.commons.testing.UtilityClassTestUtil.assertUtilityClassWellDefined; | ||
import static org.hamcrest.CoreMatchers.instanceOf; | ||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.junit.Assert.assertThat; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
import java.lang.reflect.Method; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import org.junit.Test; | ||
|
||
public class ReflectionUtilTest { | ||
|
||
@Test | ||
public void shouldBeWellDefinedUtilityClass() { | ||
assertUtilityClassWellDefined(ReflectionUtil.class); | ||
} | ||
|
||
@Test | ||
public void shouldReturnListOfMethods() throws Exception { | ||
final List<Method> methods = ReflectionUtil.methodsOf(TestClass.class); | ||
|
||
assertThat(methods.size(), is(2)); | ||
assertThat(methods.get(0).getName(), is("method1")); | ||
assertThat(methods.get(1).getName(), is("method2")); | ||
} | ||
|
||
@Test | ||
public void shouldReturnTheFirstMethod() throws Exception { | ||
final Optional<Method> method = ReflectionUtil.firstMethodOf(TestClass.class); | ||
|
||
assertThat(method.isPresent(), is(true)); | ||
assertThat(method.get().getName(), is("method1")); | ||
} | ||
|
||
@Test | ||
public void shouldReturnTheNamedMethod() throws Exception { | ||
final Optional<Method> method = ReflectionUtil.methodOf(TestClass.class, "method2"); | ||
|
||
assertThat(method.isPresent(), is(true)); | ||
assertThat(method.get().getName(), is("method2")); | ||
} | ||
|
||
@Test | ||
public void shouldReturnAnnotatedMethod() throws Exception { | ||
final Optional<Method> method = ReflectionUtil.annotatedMethod(AnnotatedTestClass.class, TestAnnotation.class); | ||
|
||
assertThat(method.isPresent(), is(true)); | ||
assertThat(method.get().getName(), is("method2")); | ||
} | ||
|
||
@Test | ||
public void shouldReturnOptionalEmptyIfNoMethodWithAnnotation() throws Exception { | ||
final Optional<Method> method = ReflectionUtil.annotatedMethod(TestClass.class, TestAnnotation.class); | ||
|
||
assertThat(method, is(Optional.empty())); | ||
} | ||
|
||
@Test | ||
public void shouldGetAndSetFieldValues() throws Exception { | ||
final TestClass testClass = new TestClass(); | ||
|
||
final Optional<Object> fieldValue = ReflectionUtil.fieldValue(testClass, "field1"); | ||
|
||
assertThat(fieldValue.isPresent(), is(true)); | ||
assertThat(fieldValue.get(), is(instanceOf(String.class))); | ||
assertThat(fieldValue.get(), is("value1")); | ||
|
||
ReflectionUtil.setField(testClass, "field1", "new value"); | ||
final Optional<String> resultValue = ReflectionUtil.fieldValue(testClass, "field1", String.class); | ||
|
||
assertThat(resultValue.isPresent(), is(true)); | ||
assertThat(resultValue.get(), is("new value")); | ||
} | ||
|
||
@Documented | ||
@Target(METHOD) | ||
@Retention(RUNTIME) | ||
@interface TestAnnotation { | ||
} | ||
|
||
private class TestClass { | ||
|
||
private String field1 = "value1"; | ||
|
||
public void method1() { | ||
} | ||
|
||
public boolean method2() { | ||
return true; | ||
} | ||
} | ||
|
||
private class AnnotatedTestClass { | ||
|
||
public void method1() { | ||
} | ||
|
||
@TestAnnotation | ||
public boolean method2() { | ||
return true; | ||
} | ||
} | ||
} |