You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/04/07 23:17:07 UTC
svn commit: r1090021 -
/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
Author: hlship
Date: Thu Apr 7 21:17:07 2011
New Revision: 1090021
URL: http://svn.apache.org/viewvc?rev=1090021&view=rev
Log:
TAP5-853: Convert PropertyShadowBuilderImpl to use PlasticProxyFactory
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java?rev=1090021&r1=1090020&r2=1090021&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java Thu Apr 7 21:17:07 2011
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,32 +14,42 @@
package org.apache.tapestry5.ioc.internal.services;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.ioc.util.BodyBuilder;
-
-import static java.lang.String.format;
-import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import org.apache.tapestry5.ioc.services.Builtin;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.InstructionBuilder;
+import org.apache.tapestry5.plastic.InstructionBuilderCallback;
+import org.apache.tapestry5.plastic.MethodDescription;
+import org.apache.tapestry5.plastic.PlasticClass;
+import org.apache.tapestry5.plastic.PlasticClassTransformer;
+import org.apache.tapestry5.plastic.PlasticField;
+import org.apache.tapestry5.plastic.PlasticMethod;
+
public class PropertyShadowBuilderImpl implements PropertyShadowBuilder
{
- private final ClassFactory classFactory;
-
private final PropertyAccess propertyAccess;
+ private final PlasticProxyFactory proxyFactory;
+
public PropertyShadowBuilderImpl(@Builtin
- ClassFactory classFactory,
+ PlasticProxyFactory proxyFactory,
PropertyAccess propertyAccess)
{
- this.classFactory = classFactory;
+ this.proxyFactory = proxyFactory;
this.propertyAccess = propertyAccess;
}
- public <T> T build(Object source, String propertyName, Class<T> propertyType)
+ public <T> T build(final Object source, final String propertyName, final Class<T> propertyType)
{
- Class sourceClass = source.getClass();
- PropertyAdapter adapter = propertyAccess.getAdapter(sourceClass).getPropertyAdapter(propertyName);
+ final Class sourceClass = source.getClass();
+ final PropertyAdapter adapter = propertyAccess.getAdapter(sourceClass).getPropertyAdapter(propertyName);
// TODO: Perhaps extend ClassPropertyAdapter to do these checks?
@@ -53,55 +63,54 @@ public class PropertyShadowBuilderImpl i
throw new RuntimeException(ServiceMessages.propertyTypeMismatch(propertyName, sourceClass,
adapter.getType(), propertyType));
- ClassFab cf = classFactory.newClass(propertyType);
-
- cf.addField("_source", Modifier.PRIVATE | Modifier.FINAL, sourceClass);
-
- cf.addConstructor(new Class[]
- { sourceClass }, null, "_source = $1;");
-
- BodyBuilder body = new BodyBuilder();
- body.begin();
-
- body.addln("%s result = _source.%s();", sourceClass.getName(), adapter.getReadMethod().getName());
-
- body.addln("if (result == null)");
- body.begin();
- body.addln("throw new NullPointerException(%s.buildMessage(_source, \"%s\"));", getClass().getName(),
- propertyName);
- body.end();
-
- body.addln("return result;");
-
- body.end();
-
- MethodSignature sig = new MethodSignature(propertyType, "_delegate", null, null);
- cf.addMethod(Modifier.PRIVATE, sig, body.toString());
-
- String toString = format("<Shadow: property %s of %s>", propertyName, source);
-
- cf.proxyMethodsToDelegate(propertyType, "_delegate()", toString);
-
- Class shadowClass = cf.createClass();
-
- try
+ ClassInstantiator instantiator = proxyFactory.createProxy(propertyType, new PlasticClassTransformer()
{
- Constructor cc = shadowClass.getConstructors()[0];
-
- Object instance = cc.newInstance(source);
+ public void transform(PlasticClass plasticClass)
+ {
+ final PlasticField sourceField = plasticClass.introduceField(sourceClass, "source").inject(source);
+
+ PlasticMethod delegateMethod = plasticClass.introduceMethod(new MethodDescription(Modifier.PRIVATE,
+ 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(0);
+
+ builder.ifNull(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.throwException(
+ NullPointerException.class,
+ String.format(
+ "Unable to delegate method invocation to property '%s' of %s, because the property is null.",
+ propertyName, source));
+ }
+ }, null);
+
+ builder.returnResult();
+ }
+ });
+
+ for (Method m : propertyType.getMethods())
+ {
+ plasticClass.introduceMethod(m).delegateTo(delegateMethod);
+ }
+
+ plasticClass.addToString(String.format("<Shadow: property %s of %s>", propertyName, source));
+ }
+ });
- return propertyType.cast(instance);
- }
- catch (Exception ex)
- {
- // Should not be reachable
- throw new RuntimeException(ex);
- }
-
- }
-
- public static final String buildMessage(Object source, String propertyName)
- {
- return String.format("Unable to delegate method invocation to property '%s' of %s, because the property is null.", propertyName, source);
+ return propertyType.cast(instantiator.newInstance());
}
}