In order to make some assertions in a Java project’s automated test suite, I needed to get the list of private, protected and public members of an object.
Using
Class#getDeclaredFieldNames()
,
you can easily get a class’s
Field
s,
an example of reflection in Java:
Class<?> someClass = someObject.getClass();
Field[] declaredFields = someClass.getDeclaredFields();
For our purposes, we’ll get that as a stream:
Stream<Field> declaredFields = Arrays.stream(
someClass.getDeclaredFields()
);
Unfortunately, this only returns the class’s direct fields. It doesn’t include fields from parent classes. But we can do that with a recursive function:
package com.alphahydrae.example;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.stream.Stream;
public final class FieldUtils {
public static Stream<Field> streamFields(
Class<?> currentClass
) {
// The stop condition for the recursive function: when we
// run out of parent classes, return an empty stream.
if (currentClass == null) {
return Stream.empty();
}
// Return the stream of the parent class's fields
// concatenated to the current class's.
return Stream.concat(
streamFields(currentClass.getSuperclass()),
Arrays.stream(currentClass.getDeclaredFields())
);
}
private FieldUtils() {}
}
Using the functional powers granted to us by streams, we can easily:
- Filter out the fields we don’t want (in this case I did not want static fields to be listed);
- Get the names of the fields.
// ...
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.stream.Collectors;
public final class FieldUtils {
// ...
public static List<String> getDeclaredFieldNames(
Object object
) {
return getFields(object.getClass())
// Filter out static fields.
.filter(field ->
!Modifier.isStatic(field.getModifiers()))
// Get the names.
.map(Field::getName)
// Collect them into a list.
.collect(Collectors.toList());
}
// ...
}
Done.
Here’s how you could use it:
// PersonDto.java
public class PersonDto {
public String firstName;
public String lastName;
}
// EmployeeDto.java
public class EmployeeDto extends PersonDto {
public String employeeNo;
}
// EmployeeDtoTests.java
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import org.junit.jupiter.api.Test;
public class EmployeeDtoTests {
@Test
void employeeDtoFieldsHaveNotChanged() {
assertThat(
FieldUtils.getDeclaredFieldNames(new EmployeeDto()),
containsInAnyOrder(
"firstName",
"lastName",
"employeeNo"
)
);
}
}