Question

I was looking for some utility class/code that would take a java bean and initialize all its values to random values. It could be done via reflection as some libraries already create the toString() or equals() methods. Is is useful while developing the UI to have some data for example.

Other possible nice to haves:

  1. recursively initialize non primitive or simple (string, date) members too
  2. initialize a collection of beans
  3. maybe give some way to limit the values generated, for example for numbers we could give ranges, for strings regexps or wildcards...

somebody knows something like this? thanks

EDIT: resolving...Got Apocalisp's sample working and definitively is what I was looking for. It has some drawbacks IMHO:

  • The library has a much larger scope than that use, but this is not a problem for me
  • It's quite complicated to understand how to build the Arbitrary for your objects unless you invest some time to study the whole thing. This is a drawback.
  • And it could be more succint I guess, but that is fine too.

thanks!

Was it helpful?

Solution

Take a look at the Gen class from the Reductio library. This is part of a highly configurable framework for generating arbitrary values of more or less any type. Generators for primitive types and most of the Java collections classes are provided. You should be able to create Arbitrary instances for your classes fairly easily.

EDIT Here's the example, corrected:

import static fj.test.Arbitrary.*;
import static fj.Function.*;

static final Arbitrary<Person> personArbitrary =
  arbitrary(arbInteger.gen.bind(arbString.gen, arbBoolean.gen,
      curry(new F3<Integer, String, Boolean, Person>() {
        public Person f(final Integer age, final String name, final Boolean male)
          {return new Person(age, name, male);}})));

Then generate an arbitrary Person of "size 100" like so. I.e. it will have a name of 100 characters at most.

Person p = personArbitrary.gen.gen(100, Rand.standard);

OTHER TIPS

Take a look at Random Beans:

https://github.com/benas/random-beans

It allows you to populate a Java Object graph with random data.

Hope it helps

Kind regards

While I did notice that this post may be a bit old, I just happened to have the same necessity, and none of the presented solutions quite seemed to solve it acceptably, so I did some quick-and-dirty fifteen-minute not-quite-generic utility method for generating randomly populated beans, which may or may not be useful for someone else who happens to have a similar problem:

import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Random;

import org.springframework.beans.BeanUtils;

public class RandomBeanUtil {

    public static <T> Collection<T> generateTestData(Class<T> clazz, int quantity) {
        Collection<T> list = new ArrayList<T>();

        PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(clazz);
        Random rand = new Random();

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        try {
            for (int i = 0; i != quantity; i++) {
                    T o = clazz.newInstance();

                    for (PropertyDescriptor descriptor : descriptors) {
                        Class<?> type = descriptor.getPropertyType();
                        if (String.class.isAssignableFrom(type)) {
                            descriptor.getWriteMethod().invoke(o, String.valueOf(new char[]{
                                    (char)('A' + rand.nextInt(26)), (char)('a' + rand.nextInt(26)) }));
                        } else if (Date.class.isAssignableFrom(type)) {
                            cal.add(Calendar.DATE, rand.nextInt(60) - 30);
                            descriptor.getWriteMethod().invoke(o, cal.getTime());
                        } else if (BigDecimal.class.isAssignableFrom(type)) {
                            descriptor.getWriteMethod().invoke(o, 
                                    new BigDecimal(rand.nextDouble() * 500).setScale(2, RoundingMode.HALF_UP));
                        }
                    }

                    list.add(o);
            }       
        } catch (Exception e) {
            // TODO: Improve exception handling
            throw new RuntimeException("Error while generating the bean collection", e);
        }

        return list;
    }

}

I don't have a library for you but if you get a random generator, then maybe this class can come in handy:

public class BeanMethodIterator implements Iterable<Method> {

    private static final int MODIFIER_FILTER = (Modifier.PUBLIC | Modifier.STATIC);
    private static final int MODIFIER_EXPECTED = Modifier.PUBLIC;

    /**
     * Indicator to filter getter or setter methods. 
     */
    public enum Filter {

        /** Only getter methods. */
        GETTERS(new Transform<Method, Boolean>(){
            public Boolean transform(Method input) {
                return (input.getName().startsWith("get") || 
                        input.getName().startsWith("is")) 
                    &&  input.getParameterTypes().length == 0;
            };
        }),

        /** Only setter methods. */
        SETTTERS(new Transform<Method, Boolean>(){
            public Boolean transform(Method input) {
                return input.getName().startsWith("set") && 
                    input.getParameterTypes().length == 1;
            };
        }),

        /** Getter and setter methods. */
        BOTH(new Transform<Method, Boolean>(){
            public Boolean transform(Method input) {
                return Filter.SETTTERS.condition.transform(input) || 
                    Filter.GETTERS.condition.transform(input);
            };
        });

        private Transform<Method, Boolean> condition;

        private Filter(Transform<Method, Boolean> condition) {
            this.condition = condition;
        }

    };

    /**
     * Iterate parent methods also?
     */
    public enum Scope {
        PARENTS_ALSO() {
            @Override
            protected Method[] getMethods(Class<?> c) {
                return c.getMethods();
            };
        },
        THIS_CLASS_ONLY() {
            @Override
            protected Method[] getMethods(Class<?> c) {
                return c.getDeclaredMethods();
            }
        };

        protected abstract Method[] getMethods(Class<?> c);
    }

    private final Filter filter;
    private final Scope scope;
    private final Class<?> theClass;

    /**
     * Constructor. 
     *
     * @param theClass
     * @param what
     */
    public BeanMethodIterator(Class<?> theClass, Filter what, Scope scope) {
        this.filter = what;
        this.theClass = theClass;
        this.scope = scope;
    }

    /**
     * Constructor. 
     */
    public BeanMethodIterator(Class<?> theClass) {
        this(theClass, Filter.BOTH, Scope.PARENTS_ALSO);
    }

    /**
     * Tells if a method is public
     * @param method
     * @return
     */
    private static boolean isPublic(Method method) {
        return (method.getModifiers() & MODIFIER_FILTER) == MODIFIER_EXPECTED; 
    }

    /**
     * {@inheritDoc}
     * @see java.lang.Iterable#iterator()
     */
    public Iterator<Method> iterator() {
        final Method[] methods = this.scope.getMethods(this.theClass);        

        return new Iterator<Method>() {
            int index = 0;

            public boolean hasNext() {
                while (index < methods.length) {
                    if (isPublic(methods[index]) && filter.condition.transform(methods[index]))
                        return true;
                    index++;
                }
                return false;
            }

            public Method next() {
                if (!hasNext())
                    throw new NoSuchElementException();
                return methods[index++];
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

    public static void main(String[] args) {
        for (Method m: new BeanMethodIterator(Date.class, Filter.GETTERS, Scope.THIS_CLASS_ONLY)) {
            System.out.println(m.getName());
        }
    }

}


/**
 * Represents a function that takes one input and returns a transformation of that input value i.e.
 * a transformation. The name Transform is used because it is shorter.
 * 
 * @author Hannes de Jager
 * @since 01 Sep 2008
 */
interface Transform<I, O> {

    /**
     * Invokes the function, performing the transformation, to produce an interpreted value.
     * 
     * @param input the input value.
     * @return The computed result.
     */
    public O transform(I input);
}

Apache Commons BeanUtils (http://commons.apache.org/beanutils) might be useful for you. There is not any utility you could use out-of-the-box, but I guess all the building blocks are there i.e. access to properties, random generators.

You can do what you would like to accomplish with the InPUT open-source library. It uses XML descriptor-based range definitions, rather than in-code definitions. InPUT uses method and constructor injection, supporting complex object structures of arbitrary initialization depth. Examples, and Tutorials are available.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top