}
public <T> T build(final Object source, final String propertyName, final Class<T> propertyType)
{
final Class sourceClass = source.getClass();
final PropertyAdapter adapter = propertyAccess.getAdapter(sourceClass).getPropertyAdapter(propertyName);
// TODO: Perhaps extend ClassPropertyAdapter to do these checks?
if (adapter == null)
throw new RuntimeException(ServiceMessages.noSuchProperty(sourceClass, propertyName));
if (!adapter.isRead())
throw new RuntimeException(ServiceMessages.readNotSupported(source, propertyName));
if (!propertyType.isAssignableFrom(adapter.getType()))
throw new RuntimeException(ServiceMessages.propertyTypeMismatch(propertyName, sourceClass,
adapter.getType(), propertyType));
ClassInstantiator instantiator = proxyFactory.createProxy(propertyType, new PlasticClassTransformer()
{
public void transform(PlasticClass plasticClass)
{
final PlasticField sourceField = plasticClass.introduceField(sourceClass, "source").inject(source);
PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(propertyType.getName(),
"readProperty", null, null);
// You don't do this using MethodAdvice, because then we'd have to use reflection to access the read
// method.
delegateMethod.changeImplementation(new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
builder.loadThis().getField(sourceField);
builder.invoke(sourceClass, propertyType, adapter.getReadMethod().getName());
// Now add the null check.
builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
{