package nl.tudelft.simulation.introspection.fields;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import nl.tudelft.simulation.introspection.Introspector;
import nl.tudelft.simulation.introspection.Property;
/**
* The IntrospectionField introspector provides a field manipulation implementation of the introspection interfaces. Its
* behavior adhers to the following:
*
* - Properties are discovered by searching for an object's fields (visibility neutral)
* - Property value are manipulated by setting field values (visibility neutral)
*
*
* (c) copyright 2002-2014 Delft University of Technology.
* BSD-style license. See DSOL License.
* @author Peter Jacobs.
* @author Alexander Verbraeck.
* @author Niels Lang.
* @since 1.5
*/
public class FieldIntrospector implements Introspector
{
/** useDeepIntrospection. */
private boolean useDeepIntrospection = true;
/**
* constructs a new FieldIntrospector.
*/
public FieldIntrospector()
{
this(false);
}
/**
* constructs a new FieldIntrospector.
* @param useDeepIntrospection whether to use deep introspection
*/
public FieldIntrospector(final boolean useDeepIntrospection)
{
this.useDeepIntrospection = useDeepIntrospection;
}
/** {@inheritDoc} */
@Override
public Property[] getProperties(final Object introspected)
{
Set props = new HashSet();
try
{
Field[] fields = collectFields(introspected.getClass());
for (int i = 0; i < fields.length; i++)
{
props.add(new FieldProperty(introspected, fields[i]));
}
}
catch (Exception e)
{
throw new IllegalArgumentException(this + " - getProperties", e);
}
return props.toArray(new Property[props.size()]);
}
/**
* Collect the fields for the given class, taking the preference for deep introspection into account.
* @param clasz the class to use
* @return Field[] the fields
*/
private Field[] collectFields(final Class> clasz)
{
List fields = new ArrayList(10);
this.addFields(fields, clasz, this.useDeepIntrospection);
return fields.toArray(new Field[fields.size()]);
}
/**
* Add fields of 'clasz' to the fieldList. Optionally iterate over the class hierarchy.
* @param fieldList the fieldList
* @param clasz the class
* @param iterate whether to iterate
*/
private void addFields(final List fieldList, final Class> clasz, final boolean iterate)
{
fieldList.addAll(Arrays.asList(clasz.getDeclaredFields()));
if (iterate && clasz.getSuperclass() != null)
{
addFields(fieldList, clasz.getSuperclass(), iterate);
}
}
/** {@inheritDoc} */
@Override
public Property getProperty(final Object introspected, final String property)
{
try
{
Field[] fields = collectFields(introspected.getClass());
for (int i = 0; i < fields.length; i++)
{
if (fields[i].getName().equals(property))
{
return new FieldProperty(introspected, fields[i]);
}
}
}
catch (Exception e)
{
throw new IllegalArgumentException(this + " - getProperty", e);
}
throw new IllegalArgumentException("Property '" + property + "' not found for " + introspected);
}
/** {@inheritDoc} */
@Override
public String[] getPropertyNames(final Object introspected)
{
Set props = new HashSet();
try
{
Field[] fields = collectFields(introspected.getClass());
for (int i = 0; i < fields.length; i++)
{
props.add(fields[i].getName());
}
}
catch (Exception e)
{
throw new IllegalArgumentException(this + " - getPropertyNames", e);
}
return props.toArray(new String[props.size()]);
}
}