Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
Add ReflectionUtil
Browse files Browse the repository at this point in the history
  • Loading branch information
mapingo committed Oct 3, 2017
1 parent 32640e1 commit 99509a5
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 3 deletions.
5 changes: 2 additions & 3 deletions test-utils-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>com.btmatthews.hamcrest</groupId>
<artifactId>hamcrest-matchers</artifactId>
Expand Down
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();
}
}
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;
}
}
}

0 comments on commit 99509a5

Please sign in to comment.