Skip to content

Commit 681e6a3

Browse files
committed
refactor: use SpecimenType instead of Class
This simplifies the reflector by reducing the number of constructors as well as the number of arguments for validation.
1 parent a7d56e9 commit 681e6a3

File tree

5 files changed

+28
-32
lines changed

5 files changed

+28
-32
lines changed

src/main/java/com/github/nylle/javafixture/Reflector.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,15 @@
1818

1919
public class Reflector<T> {
2020
private final T instance;
21-
private final Class<?> clazz;
21+
private final SpecimenType<T> type;
2222

23-
public Reflector(T instance) {
24-
this(instance, instance.getClass());
25-
}
26-
27-
public Reflector(T instance, Class<?> clazz) {
23+
public Reflector(T instance, SpecimenType<T> type) {
2824
this.instance = instance;
29-
this.clazz = clazz;
25+
this.type = type;
3026
}
3127

32-
public Reflector<T> validateCustomization(CustomizationContext customizationContext, SpecimenType<T> type) {
33-
var declaredFields = getDeclaredFields(clazz).map(field -> field.getName()).collect(toList());
28+
public Reflector<T> validateCustomization(CustomizationContext customizationContext) {
29+
var declaredFields = getDeclaredFields(type.asClass()).map(field -> field.getName()).collect(toList());
3430

3531
var missingDeclaredField = Stream.concat(customizationContext.getCustomFields().keySet().stream(), customizationContext.getIgnoredFields().stream())
3632
.map(entry -> entry.replaceAll("\\..+", ""))
@@ -41,7 +37,7 @@ public Reflector<T> validateCustomization(CustomizationContext customizationCont
4137
throw new SpecimenException(format("Cannot customize field '%s': Field not found in class '%s'.", missingDeclaredField.get(), type.getName()));
4238
}
4339

44-
var duplicateField = getDeclaredFields(clazz)
40+
var duplicateField = getDeclaredFields(type.asClass())
4541
.collect(groupingBy(field -> field.getName()))
4642
.entrySet()
4743
.stream()
@@ -52,7 +48,7 @@ public Reflector<T> validateCustomization(CustomizationContext customizationCont
5248
.findFirst();
5349

5450
if (duplicateField.isPresent()) {
55-
throw new SpecimenException(format("Cannot customize field '%s'. Duplicate field names found: \n%s",
51+
throw new SpecimenException(format("Cannot customize field '%s'. Duplicate field names found: %n%s",
5652
duplicateField.get().getKey(),
5753
duplicateField.get().getValue().stream().map(x -> x.toString()).collect(joining("\n"))));
5854
}
@@ -61,12 +57,12 @@ public Reflector<T> validateCustomization(CustomizationContext customizationCont
6157
}
6258

6359
public Stream<Field> getDeclaredFields() {
64-
return getDeclaredFields(clazz);
60+
return getDeclaredFields(type.asClass());
6561
}
6662

6763
public Annotation[] getFieldAnnotations(Field field) {
6864
try {
69-
return Stream.concat(Arrays.stream(Introspector.getBeanInfo(clazz).getPropertyDescriptors())
65+
return Stream.concat(Arrays.stream(Introspector.getBeanInfo(type.asClass()).getPropertyDescriptors())
7066
.filter(property -> !Modifier.isStatic(field.getModifiers()))
7167
.filter(property -> property.getName().equals(field.getName()))
7268
.flatMap(propertyDescriptor -> Stream.of(propertyDescriptor.getReadMethod(), propertyDescriptor.getWriteMethod())
@@ -82,9 +78,9 @@ public void setField(Field field, Object value) {
8278
field.setAccessible(true);
8379
field.set(instance, value);
8480
} catch (SecurityException e) {
85-
throw new SpecimenException(format("Unable to access field %s on object of type %s", field.getName(), clazz.getName()), e);
81+
throw new SpecimenException(format("Unable to access field %s on object of type %s", field.getName(), type.getName()), e);
8682
} catch (IllegalAccessException | InaccessibleObjectException e) {
87-
throw new SpecimenException(format("Unable to set field %s on object of type %s", field.getName(), clazz.getName()), e);
83+
throw new SpecimenException(format("Unable to set field %s on object of type %s", field.getName(), type.getName()), e);
8884
}
8985
}
9086

src/main/java/com/github/nylle/javafixture/specimen/AbstractSpecimen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public T create(final CustomizationContext customizationContext, Annotation[] an
5050

5151
try {
5252
var result = (T) context.cached(type, instanceFactory.proxy(type));
53-
var reflector = new Reflector<>(result, type.asClass()).validateCustomization(customizationContext, type);
53+
var reflector = new Reflector<>(result, type).validateCustomization(customizationContext);
5454
reflector.getDeclaredFields()
5555
.filter(field -> !customizationContext.getIgnoredFields().contains(field.getName()))
5656
.forEach(field -> reflector.setField(field,

src/main/java/com/github/nylle/javafixture/specimen/GenericSpecimen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public T create(CustomizationContext customizationContext, Annotation[] annotati
7272

7373
private T populate(CustomizationContext customizationContext) {
7474
var result = context.cached(type, instanceFactory.instantiate(type));
75-
var reflector = new Reflector<>(result).validateCustomization(customizationContext, type);
75+
var reflector = new Reflector<>(result, type).validateCustomization(customizationContext);
7676
try {
7777
reflector.getDeclaredFields()
7878
.filter(field -> !customizationContext.getIgnoredFields().contains(field.getName()))

src/main/java/com/github/nylle/javafixture/specimen/ObjectSpecimen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public T create(CustomizationContext customizationContext, Annotation[] annotati
5757

5858
private T populate(CustomizationContext customizationContext) {
5959
var result = context.cached(type, instanceFactory.instantiate(type));
60-
var reflector = new Reflector<>(result).validateCustomization(customizationContext, type);
60+
var reflector = new Reflector<>(result, type).validateCustomization(customizationContext);
6161
try {
6262
reflector.getDeclaredFields()
6363
.filter(field -> !customizationContext.getIgnoredFields().contains(field.getName()))

src/test/java/com/github/nylle/javafixture/ReflectorTest.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,24 @@ class ValidateCustomization {
3636
@DisplayName("with existing fields, nothing happens")
3737
void validCustomization() {
3838

39-
var sut = new Reflector<>(new GenericChild<String>());
39+
var sut = new Reflector<>(new GenericChild<String>(), new SpecimenType<>(){});
4040

4141
var validCustomisation = new CustomizationContext(List.of(), Map.of("baseField.subField", "foo"), false);
4242

43-
assertThatCode(() -> sut.validateCustomization(validCustomisation, new SpecimenType<>() {}))
43+
assertThatCode(() -> sut.validateCustomization(validCustomisation))
4444
.doesNotThrowAnyException();
4545
}
4646

4747
@Test
4848
@DisplayName("with any missing fields, an exception is thrown")
4949
void invalidCustomization() {
5050

51-
var sut = new Reflector<>(new GenericChild<String>());
51+
var sut = new Reflector<>(new GenericChild<String>(), new SpecimenType<>() {});
5252

5353
var invalidCustomisation = new CustomizationContext(List.of(), Map.of("nonExistingField.subField", "foo"), false);
5454

5555
assertThatExceptionOfType(SpecimenException.class)
56-
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation, new SpecimenType<>() {}))
56+
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation))
5757
.withMessage("Cannot customize field 'nonExistingField': Field not found in class 'com.github.nylle.javafixture.testobjects.inheritance.GenericChild<java.lang.String>'.")
5858
.withNoCause();
5959
}
@@ -62,14 +62,14 @@ void invalidCustomization() {
6262
@DisplayName("to set duplicate fields, an exception is thrown")
6363
void customizingDuplicateFields() {
6464

65-
var sut = new Reflector<>(new GenericChild<String>());
65+
var sut = new Reflector<>(new GenericChild<String>(), new SpecimenType<>(){});
6666

6767
Map<String, Object> customization = Map.of("fieldIn2Classes.subField", 100.0);
6868

6969
var invalidCustomisation = new CustomizationContext(List.of(), customization, false);
7070

7171
assertThatExceptionOfType(SpecimenException.class)
72-
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation, new SpecimenType<>() {}))
72+
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation))
7373
.withMessageContaining("Cannot customize field 'fieldIn2Classes'. Duplicate field names found:")
7474
.withMessageContaining("private java.lang.Double com.github.nylle.javafixture.testobjects.inheritance.GenericParent.fieldIn2Classes")
7575
.withMessageContaining("private java.lang.Integer com.github.nylle.javafixture.testobjects.inheritance.GenericBase.fieldIn2Classes")
@@ -80,14 +80,14 @@ void customizingDuplicateFields() {
8080
@DisplayName("to omit duplicate fields, an exception is thrown")
8181
void omittingDuplicateFields() {
8282

83-
var sut = new Reflector<>(new GenericChild<String>());
83+
var sut = new Reflector<>(new GenericChild<String>(), new SpecimenType<>(){});
8484

8585
var omitting = List.of("fieldIn2Classes.subField");
8686

8787
var invalidCustomisation = new CustomizationContext(omitting, Map.of(), false);
8888

8989
assertThatExceptionOfType(SpecimenException.class)
90-
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation, new SpecimenType<>() {}))
90+
.isThrownBy(() -> sut.validateCustomization(invalidCustomisation))
9191
.withMessageContaining("Cannot customize field 'fieldIn2Classes'. Duplicate field names found:")
9292
.withMessageContaining("private java.lang.Double com.github.nylle.javafixture.testobjects.inheritance.GenericParent.fieldIn2Classes")
9393
.withMessageContaining("private java.lang.Integer com.github.nylle.javafixture.testobjects.inheritance.GenericBase.fieldIn2Classes")
@@ -103,7 +103,7 @@ class SetField {
103103
@Test
104104
void catchIllegalAccessException() throws Exception {
105105
var mockedField = Mockito.mock(Field.class);
106-
var sut = new Reflector<>("");
106+
var sut = new Reflector<>("", new SpecimenType<>(){});
107107
doThrow(new IllegalAccessException("expected")).when(mockedField).set(any(), any());
108108

109109
assertThatExceptionOfType(SpecimenException.class)
@@ -114,7 +114,7 @@ void catchIllegalAccessException() throws Exception {
114114
@Test
115115
void catchSecurityException() {
116116
var mockedField = Mockito.mock(Field.class);
117-
var sut = new Reflector<>("");
117+
var sut = new Reflector<>("", new SpecimenType<>(){});
118118
doThrow(new SecurityException("expected")).when(mockedField).setAccessible(true);
119119
assertThatExceptionOfType(SpecimenException.class)
120120
.isThrownBy(() -> sut.setField(mockedField, ""));
@@ -124,7 +124,7 @@ void catchSecurityException() {
124124
@Test
125125
void catchInaccessibleObjectException() {
126126
var mockedField = Mockito.mock(Field.class);
127-
var sut = new Reflector<>("");
127+
var sut = new Reflector<>("", new SpecimenType<>(){});
128128
doThrow(new InaccessibleObjectException("expected")).when(mockedField).setAccessible(true);
129129
assertThatExceptionOfType(SpecimenException.class)
130130
.isThrownBy(() -> sut.setField(mockedField, ""));
@@ -136,7 +136,7 @@ class GetFieldAnnotations {
136136

137137
@Test
138138
void returnsSizeAnnotationOnPrivateField() {
139-
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotations());
139+
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotations(), new SpecimenType<>(){});
140140

141141
var field = sut.getDeclaredFields().filter(x -> x.getName().equals("withMinMaxAnnotation")).findFirst().get();
142142

@@ -148,7 +148,7 @@ void returnsSizeAnnotationOnPrivateField() {
148148

149149
@Test
150150
void returnsSizeAnnotationOnGetter() {
151-
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotationsOnMethod());
151+
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotationsOnMethod(), new SpecimenType<>(){});
152152

153153
var field = sut.getDeclaredFields().filter(x -> x.getName().equals("withMinMaxAnnotation")).findFirst().get();
154154

@@ -160,7 +160,7 @@ void returnsSizeAnnotationOnGetter() {
160160

161161
@Test
162162
void returnsSizeAnnotationOnFieldIfGetterThrowsIntrospectionException() {
163-
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotations());
163+
var sut = new Reflector<>(new TestObjectWithJakartaValidationAnnotations(), new SpecimenType<>(){});
164164
var expected = sut.getDeclaredFields().filter(x -> x.getName().equals("withMinMaxAnnotation")).findFirst().get().getAnnotations();
165165

166166
var throwingField = mock(Field.class);

0 commit comments

Comments
 (0)