com.gregmarut.support.beangenerator.BeanPropertyFieldInitializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of test-beangen Show documentation
Show all versions of test-beangen Show documentation
Supports unit testing by dynamically creating bean objects and populating their fields to default values.
/*******************************************************************************
*
* Copyright (c) 2015 Greg Marut.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Greg Marut - initial API and implementation
*
******************************************************************************/
package com.gregmarut.support.beangenerator;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Collection;
import com.gregmarut.support.beangenerator.cache.Cache;
import com.gregmarut.support.beangenerator.cache.Retrieve;
import com.gregmarut.support.beangenerator.rule.Rule;
import com.gregmarut.support.util.ReflectionUtil;
/**
* This class is responsible for the actual initialization of a bean object. It uses reflection to cascade an object
* looking for all declared fields and create a new instance of that class.
*
* @author Greg Marut
*/
public final class BeanPropertyFieldInitializer extends BeanPropertyInitializer
{
/**
* Constructs a new BeanPropertyInitializer
*
* @param properties
*/
BeanPropertyFieldInitializer(final Properties properties, final Cache cache)
{
super(properties, cache);
}
protected void populate(final Object object)
{
// retrieve a list of all of the methods defined in this class
Field[] fields = ReflectionUtil.getAllFields(object);
// set the data on the object
setData(object, fields);
// populate the collections in this object with test data
populateCollections(object, fields);
}
/**
* Sets the data on the object
*
* @param obj
* @param setterMethods
*/
private void setData(final Object obj, final Field[] fields)
{
// for each of the fields in the list
for (Field field : fields)
{
// make sure this field is not transient and its not final
if (!Modifier.isTransient(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()))
{
// get the type of this field
Class> clazz = field.getType();
try
{
// holds the value to set for this field
Object value;
// attempt to see if a rule generated value exists for this parameter type and
// setter method
Rule> rule = checkForMatchingRule(field, clazz);
// check to see if a value was found based on the rules
if (null == rule)
{
// holds the value to set in the setter method
value = getValue(field, clazz);
}
else
{
logger.debug("Rule found for \"{}\":{}", field.getName(), clazz.getName());
// set the value to the value defined in the rule
value = rule.getValue().getValue(field);
}
// set the value on the object
field.setAccessible(true);
field.set(obj, value);
}
catch (InstantiationException e)
{
// This condition typically occurs with data types that aren't currently
// supported.
// Info log level is used here rather than Error or Warn because there are cases
// where we don't mind if some fields are not initialized.
// One type that we've seen is JAXBElement, which can't
// be set to generated values without more info (such as namespace).
// However, some other fields in the object that are not of type JAXBElement
// will get set, and depending on the test case, this may be fine.
logger.info("Could not intialize property named: {} of type: {} in object of type: {}",
field.getName(), clazz.getName(), obj.getClass().getCanonicalName());
}
catch (IllegalArgumentException e)
{
logger.error(e.getMessage(), e);
}
catch (IllegalAccessException e)
{
logger.error(e.getMessage(), e);
}
}
}
}
/**
* Converts a parameter type to a value to be set onto the method.
*
* @param setterMethod
* @param clazz
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Object getValue(final Field field, final Class> clazz) throws InstantiationException,
IllegalAccessException
{
// holds the value of the object to return
final Object obj;
// make sure the parameter is not null
if (null != clazz)
{
// check to see if this parameter is a type of collection
if (Collection.class.isAssignableFrom(clazz))
{
// instantiate a new collection object
Collection> collection = (Collection>) instantiate(clazz);
// assign the collection as the object to set into the method
obj = collection;
}
else
{
// check to see if this value exists in the default values map
if (properties.getDefaultValues().containsKey(clazz))
{
logger.debug("Found default value for \"{}\":{}", field.getName(), clazz.getName());
// retrieve the default value
obj = properties.getDefaultValues().get(clazz).getValue(field);
}
else
{
// create the object that instructs how to retrieve the object
Retrieve