package org.tynamo.descriptor.factories;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tynamo.descriptor.TynamoClassDescriptor;
import org.tynamo.descriptor.TynamoClassDescriptorImpl;
import org.tynamo.descriptor.decorators.DescriptorDecorator;
import org.tynamo.exception.TynamoRuntimeException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**
* Generate descriptors using reflection on the underlying class.
* ReflectionDescriptorFactory.buildClassDescriptor() is the only public method
* here.
*/
public class ReflectionDescriptorFactory implements DescriptorFactory
{
private static final Logger logger = LoggerFactory.getLogger(ReflectionDescriptorFactory.class);
private final MethodDescriptorFactory methodDescriptorFactory;
private final PropertyDescriptorFactory propertyDescriptorFactory;
private final List<DescriptorDecorator> decorators;
/**
* @param decorators In the default Tynamo configuration this will contain a HibernateDescriptorDecorator and an TynamoDecorator
* @param methodDescriptorFactory
* @param propertyDescriptorFactory
*/
public ReflectionDescriptorFactory(final List<DescriptorDecorator> decorators, MethodDescriptorFactory methodDescriptorFactory, PropertyDescriptorFactory propertyDescriptorFactory)
{
this.decorators = decorators;
this.methodDescriptorFactory = methodDescriptorFactory;
this.propertyDescriptorFactory = propertyDescriptorFactory;
}
/**
* Given a type, build a class descriptor
*
* @param type The type to build for
* @return a completed class descriptor
*/
public TynamoClassDescriptor buildClassDescriptor(Class type)
{
try
{
TynamoClassDescriptor descriptor = new TynamoClassDescriptorImpl(type);
BeanInfo beanInfo = Introspector.getBeanInfo(type);
BeanUtils.copyProperties(descriptor, beanInfo.getBeanDescriptor());
descriptor.setPropertyDescriptors(propertyDescriptorFactory.buildPropertyDescriptors(type, beanInfo));
descriptor.setMethodDescriptors(methodDescriptorFactory.buildMethodDescriptors(type, beanInfo));
descriptor = applyDecorators(descriptor);
return descriptor;
} catch (IllegalAccessException e)
{
logger.error("couldn't build class descriptor for: " + type.getSimpleName(), e);
throw new TynamoRuntimeException(e, type);
} catch (InvocationTargetException e)
{
logger.error("couldn't build class descriptor for: " + type.getSimpleName(), e);
throw new TynamoRuntimeException(e, type);
} catch (IntrospectionException e)
{
logger.error("couldn't build class descriptor for: " + type.getSimpleName(), e);
throw new TynamoRuntimeException(e, type);
}
}
/**
* Have the decorators decorate this descriptor
*
* @param descriptor
* @return The resulting descriptor after all decorators are applied
*/
private TynamoClassDescriptor applyDecorators(final TynamoClassDescriptor descriptor)
{
TynamoClassDescriptor decoratedDescriptor = descriptor;
for (DescriptorDecorator decorator : decorators)
{
decoratedDescriptor = decorator.decorate(decoratedDescriptor);
}
return decoratedDescriptor;
}
}