1111
1212import java .lang .reflect .Field ;
1313import java .lang .reflect .InvocationTargetException ;
14+ import java .util .ArrayList ;
15+ import java .util .Arrays ;
1416import java .util .HashSet ;
1517import java .util .List ;
1618import java .util .Set ;
@@ -217,10 +219,10 @@ private static <P> Stream<?> getValues(Rule rule, P parameterUnderTest) {
217219 private static <T > T createCopyWithAlteredProperty (T original , String property , Object alteredValue ) {
218220 try {
219221 // Get the class of the original object
220- var clazz = original .getClass ();
222+ var clazz = ( Class < T >) original .getClass ();
221223
222224 // Get all the declared fields of the class
223- var fields = clazz . getDeclaredFields ( );
225+ var fields = getAllFields ( clazz );
224226
225227 // Create an array to hold the values of the original object's properties
226228 var propertyValues = new Object [fields .length ];
@@ -235,10 +237,6 @@ private static <T> T createCopyWithAlteredProperty(T original, String property,
235237 parameterTypes [i ] = fields [i ].getType ();
236238 }
237239
238- // Get the constructor that accepts all properties as arguments
239- var constructor = clazz .getDeclaredConstructor (parameterTypes );
240- constructor .setAccessible (true );
241-
242240 // Create an array to hold the new property values
243241 var newPropertyValues = new Object [propertyValues .length ];
244242
@@ -261,18 +259,46 @@ private static <T> T createCopyWithAlteredProperty(T original, String property,
261259 }
262260 }
263261
264- // Create a copy with the altered property value
265- return (T ) constructor .newInstance (newPropertyValues );
262+ return createCopyWithAlteredValues (clazz , parameterTypes , newPropertyValues , fields );
266263 } catch (NoSuchMethodException e ) {
267264 throw new RuleValidationException (
268- "Error creating copy with altered property. Maybe there is no all-args -constructor?" ,
265+ "Error creating copy with altered property. Maybe there is no eligible -constructor?" ,
269266 e
270267 );
271268 } catch (IllegalAccessException | InstantiationException | InvocationTargetException e ) {
272269 throw new RuleValidationException ("Error creating copy with altered property: " + property , e );
273270 }
274271 }
275272
273+ private static <T > T createCopyWithAlteredValues (
274+ Class <T > clazz ,
275+ Class <?>[] parameterTypes ,
276+ Object [] newPropertyValues ,
277+ Field [] fields
278+ ) throws InstantiationException , IllegalAccessException , InvocationTargetException , NoSuchMethodException {
279+ T instance = null ;
280+ try {
281+ // Get the constructor that accepts all properties as arguments
282+ var constructor = clazz .getDeclaredConstructor (parameterTypes );
283+ constructor .setAccessible (true );
284+
285+ // Create a copy with the altered property value
286+ instance = constructor .newInstance (newPropertyValues );
287+ } catch (NoSuchMethodException e ) {
288+ // Get the no args constructor
289+ var constructor = clazz .getDeclaredConstructor ();
290+ constructor .setAccessible (true );
291+
292+ // Create a copy with the altered property value
293+ instance = constructor .newInstance ();
294+ for (var i = 0 ; i < newPropertyValues .length ; i ++) {
295+ fields [i ].setAccessible (true );
296+ fields [i ].set (instance , newPropertyValues [i ]);
297+ }
298+ }
299+ return instance ;
300+ }
301+
276302 private static <T > Set <String > getAllPropertiesOf (T object ) {
277303 var clazz = object .getClass ();
278304
@@ -307,12 +333,23 @@ private static boolean hasNullableAnnotation(String propertyName, Object object)
307333 private static Field getFieldOrFail (String propertyName , Object object ) {
308334 var clazz = object .getClass ();
309335
310- Field field = null ;
311- try {
312- field = clazz .getDeclaredField (propertyName );
313- } catch (NoSuchFieldException e ) {
314- throw new RuleValidationException ("Property does not exist: " + propertyName , e );
336+ var field = Arrays .stream (getAllFields (clazz ))
337+ .filter (
338+ f -> f .getName ().equals (propertyName )
339+ )
340+ .findFirst ();
341+
342+ return field .orElseThrow (() -> new RuleValidationException ("Property does not exist: " + propertyName ));
343+ }
344+
345+ private static Field [] getAllFields (Class <?> initialClazz ) {
346+ Class <?> clazz = initialClazz ;
347+
348+ var fields = new ArrayList <Field >();
349+ while (clazz != null ) {
350+ fields .addAll (Arrays .asList (clazz .getDeclaredFields ()));
351+ clazz = clazz .getSuperclass ();
315352 }
316- return field ;
353+ return fields . toArray ( new Field [ 0 ]) ;
317354 }
318355}
0 commit comments