Skip to content

Commit

Permalink
#63 FieldUtils: Small adjustments (naming, javadoc, methods)
Browse files Browse the repository at this point in the history
  • Loading branch information
ljacqu committed Sep 24, 2023
1 parent f788948 commit fb2bfcd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 19 deletions.
21 changes: 16 additions & 5 deletions src/main/java/ch/jalu/typeresolver/FieldUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import java.util.stream.Collectors;

/**
* Classes with utils for handling fields.
* Class with utilities for processing fields.
*/
public final class FieldUtils {

Expand All @@ -31,8 +31,8 @@ public static String formatField(Field field) {
}

/**
* Specifies whether a field is a "regular" (= non-synthetic) instance fields. This method exists for brevity and
* because it can be easily forgotten to check if a field is synthetic.
* Specifies whether a field is a "regular" (= non-synthetic) instance field. This method exists for brevity and
* because it can be easily forgotten to exclude synthetic fields.
*
* @param field the field to process
* @return true if the field is not synthetic and not static, false otherwise
Expand All @@ -41,6 +41,17 @@ public static boolean isRegularInstanceField(Field field) {
return !field.isSynthetic() && !Modifier.isStatic(field.getModifiers());
}

/**
* Specifies whether a field is a "regular" (= non-synthetic) static field. This method exists for brevity and
* because it can be easily forgotten to exclude synthetic fields.
*
* @param field the field to process
* @return true if the field is not synthetic and static, false otherwise
*/
public static boolean isRegularStaticField(Field field) {
return !field.isSynthetic() && Modifier.isStatic(field.getModifiers());
}

/**
* Returns all fields from the given class and its parents, recursively. The fields of the top-most parent
* in this class's hierarchy are returned first.
Expand Down Expand Up @@ -91,7 +102,7 @@ public static List<Field> getFieldsIncludingParents(Class<?> clazz, Predicate<Fi
* @param clazz the class whose instance fields should be retrieved
* @return all non-synthetic instance fields
*/
public static List<Field> getRegularInstanceFieldsFromClassAndParents(Class<?> clazz) {
public static List<Field> getRegularInstanceFieldsIncludingParents(Class<?> clazz) {
return getFieldsIncludingParents(clazz, FieldUtils::isRegularInstanceField, true);
}

Expand Down Expand Up @@ -120,7 +131,7 @@ public static Optional<Field> tryFindField(Class<?> clazz, String name) {
* @param name the name of the field to look for
* @return optional with a field of the given name
*/
public static Optional<Field> tryFindFieldInClassOrParents(Class<?> clazz, String name) {
public static Optional<Field> tryFindFieldInClassOrParent(Class<?> clazz, String name) {
Class<?> currentClass = clazz;
while (currentClass != null) {
Optional<Field> field = tryFindField(currentClass, name);
Expand Down
54 changes: 40 additions & 14 deletions src/test/java/ch/jalu/typeresolver/FieldUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasSize;

/**
* Test for {@link FieldUtils}.
Expand All @@ -31,7 +39,7 @@ void shouldReturnIfIsNonSyntheticInstanceField() throws NoSuchFieldException {
Optional<Field> syntheticField = Arrays.stream(InnerClass.class.getDeclaredFields())
.findFirst();

// / when / then
// when / then
assertThat(FieldUtils.isRegularInstanceField(ArrayList.class.getDeclaredField("size")), equalTo(true));
assertThat(FieldUtils.isRegularInstanceField(HashMap.class.getDeclaredField("DEFAULT_LOAD_FACTOR")), equalTo(false));
if (syntheticField.isPresent()) {
Expand All @@ -41,6 +49,22 @@ void shouldReturnIfIsNonSyntheticInstanceField() throws NoSuchFieldException {
}
}

@Test
void shouldReturnIfIsNonSyntheticStaticField() throws NoSuchFieldException {
// given
Optional<Field> syntheticField = Arrays.stream(InnerClass.class.getDeclaredFields())
.findFirst();

// when / then
assertThat(FieldUtils.isRegularStaticField(ArrayList.class.getDeclaredField("size")), equalTo(false));
assertThat(FieldUtils.isRegularStaticField(HashMap.class.getDeclaredField("DEFAULT_LOAD_FACTOR")), equalTo(true));
if (syntheticField.isPresent()) {
assertThat(FieldUtils.isRegularStaticField(syntheticField.get()), equalTo(false));
} else {
throw new IllegalStateException("No field found in " + InnerClass.class);
}
}

@Test
void shouldGetFieldsIncludingParents() throws NoSuchFieldException {
// given / when
Expand All @@ -56,6 +80,8 @@ void shouldGetFieldsIncludingParents() throws NoSuchFieldException {
expectedFields.add(Class3.class.getDeclaredField("c3a"));
expectedFields.add(Class3.class.getDeclaredField("c3b"));

// We expect the fields to appear in the given order, but allow other fields in between because
// various plugins might add synthetic fields during test runs
Iterator<Field> expectedFieldsIterator = expectedFields.iterator();
Field expectedField = expectedFieldsIterator.next();
for (Field field : allFields) {
Expand Down Expand Up @@ -101,8 +127,8 @@ void shouldGetAllFieldsWithFilterAndParentsLast() throws NoSuchFieldException {
@Test
void shouldGetAllRegularInstanceFieldsIncludingParents() throws NoSuchFieldException {
// given / when
List<Field> allFields1 = FieldUtils.getRegularInstanceFieldsFromClassAndParents(Class3.class);
List<Field> allFields2 = FieldUtils.getRegularInstanceFieldsFromClassAndParents(InnerClass.class);
List<Field> allFields1 = FieldUtils.getRegularInstanceFieldsIncludingParents(Class3.class);
List<Field> allFields2 = FieldUtils.getRegularInstanceFieldsIncludingParents(InnerClass.class);

// then
assertThat(allFields1, hasSize(4));
Expand All @@ -125,18 +151,18 @@ void shouldReturnFieldFromClassIfExists() throws NoSuchFieldException {
@Test
void shouldReturnFieldFromClassOrParentIfExists() throws NoSuchFieldException {
// given / when / then
assertThat(FieldUtils.tryFindFieldInClassOrParents(Class3.class, "c3a"), equalTo(Optional.of(Class3.class.getDeclaredField("c3a"))));
assertThat(FieldUtils.tryFindFieldInClassOrParents(Class3.class, "c2a"), equalTo(Optional.of(Class2.class.getDeclaredField("c2a"))));
assertThat(FieldUtils.tryFindFieldInClassOrParents(Class3.class, "C1A"), equalTo(Optional.of(Class1.class.getDeclaredField("C1A"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(Class3.class, "c3a"), equalTo(Optional.of(Class3.class.getDeclaredField("c3a"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(Class3.class, "c2a"), equalTo(Optional.of(Class2.class.getDeclaredField("c2a"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(Class3.class, "C1A"), equalTo(Optional.of(Class1.class.getDeclaredField("C1A"))));

// Ensure the field lowest in the hierarchy is matched, if multiple field names have the same name
assertThat(FieldUtils.tryFindFieldInClassOrParents(ClassWithSameFieldNames.class, "c1b"), equalTo(Optional.of(ClassWithSameFieldNames.class.getDeclaredField("c1b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParents(ClassWithSameFieldNames.class, "c2b"), equalTo(Optional.of(ClassWithSameFieldNames.class.getDeclaredField("c2b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParents(ClassWithSameFieldNames.class, "c3b"), equalTo(Optional.of(Class3.class.getDeclaredField("c3b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParents(ClassWithSameFieldNames.class, "c2a"), equalTo(Optional.of(Class2.class.getDeclaredField("c2a"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(ClassWithSameFieldNames.class, "c1b"), equalTo(Optional.of(ClassWithSameFieldNames.class.getDeclaredField("c1b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(ClassWithSameFieldNames.class, "c2b"), equalTo(Optional.of(ClassWithSameFieldNames.class.getDeclaredField("c2b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(ClassWithSameFieldNames.class, "c3b"), equalTo(Optional.of(Class3.class.getDeclaredField("c3b"))));
assertThat(FieldUtils.tryFindFieldInClassOrParent(ClassWithSameFieldNames.class, "c2a"), equalTo(Optional.of(Class2.class.getDeclaredField("c2a"))));

assertThat(FieldUtils.tryFindFieldInClassOrParents(Class3.class, "bogus"), equalTo(Optional.empty()));
assertThat(FieldUtils.tryFindFieldInClassOrParents(Class3.class, ""), equalTo(Optional.empty()));
assertThat(FieldUtils.tryFindFieldInClassOrParent(Class3.class, "bogus"), equalTo(Optional.empty()));
assertThat(FieldUtils.tryFindFieldInClassOrParent(Class3.class, ""), equalTo(Optional.empty()));
}

private class InnerClass {
Expand Down

0 comments on commit fb2bfcd

Please sign in to comment.