#! env groovy @Grab(group='net.andreinc', module='mockneat', version='0.4.8') @Grab(group='org.apache.commons', module='commons-lang3', version='3.12.0') import net.andreinc.mockneat.MockNeat import org.codehaus.groovy.runtime.InvokerHelper import org.apache.commons.lang3.reflect.FieldUtils import groovy.lang.GroovyClassLoader public enum Colour { RED, BLUE, GREEN, YELLOW, WHITE, BLACK } class Tools { /* MockNeat.reflect() can fabric any object using its default lambda. Here we choose to adjust a little the object, using .type() and .field(). */ public static Object randomBuild(Class objectclass) { MockNeat mock = MockNeat.threadLocal() def r = mock.reflect(objectclass) .useDefaults(true) .type(String.class, mock.names().first()) .type(Colour.class, mock.from(Colour.class)) def randomObj = r.get() /* Caution using .field() : when the field does not exists, an exception occurs. Not immediatly, later when we call .get() */ switch(objectclass) { case Car.class: r = r .field("driver_license", mock.strings().size(6)) .field("insurance_ticket", mock.strings().size(6)) break case Scooter.class: r = r .field("insurance_ticket", mock.strings().size(6)) break } try { return r.get() } catch (IllegalArgumentException e) { // .field() error : skipped return randomObj } } } interface Shuffle { void shuffleObject() void shufflePartly(Class[] classesThatChange) } public class Vehicle implements Shuffle { String owner, driver Date released_on protected int wheel_number Boolean electrified Colour painted void shuffleObject() { def r = Tools.randomBuild(this.class) use(InvokerHelper) { this.setProperties(r.properties) } } void shufflePartly(Class[] classesThatChange = []) { if (classesThatChange) { println("Target class: " + classesThatChange) def toChangeFieldList = FieldUtils.getAllFieldsList(this.class).findAll{classesThatChange.contains(it.getType())}.name if (toChangeFieldList) { println("Target fields: " + toChangeFieldList) def r = Tools.randomBuild(this.class) use(InvokerHelper) { this.setProperties(r.properties.findAll {toChangeFieldList.contains(it.key)}) } } } else { // by convention : no params => all fields have to move this.shuffleObject() } } } @InheritConstructors public class Bicycle extends Vehicle { Bicycle() { this.wheel_number = 2 } } @InheritConstructors public class Scooter extends Vehicle { String insurance_ticket Scooter() { MockNeat mock = MockNeat.threadLocal() this.wheel_number = mock.ints().from(new int[]{2, 3}).get() } } @InheritConstructors public class Car extends Vehicle { String driver_license, insurance_ticket Car() { this.wheel_number = 4 } } GroovyClassLoader gos = new GroovyClassLoader(); ["Car", "Scooter", "Bicycle", "Vehicle"].each { cls -> println "\nA car has always 4 wheels. It'll never change because the field is protected" def x = gos.loadClass(cls, true, false )?.newInstance() println(x.dump()) println "\nLet's start changing all Strings" x.shufflePartly(String.class) println(x.dump()) println "\nNow we change the Colour, and also, again, all its Strings" x.shufflePartly(Colour.class, String.class) println(x.dump()) println "\nFinally we change all the fields" x.shuffleObject() println(x.dump()) println "\nAll fields change again" x.shufflePartly() println(x.dump()) } System.exit(0)