You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/04/14 00:22:49 UTC

svn commit: r1091938 - in /tapestry/tapestry5/trunk: tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/

Author: hlship
Date: Wed Apr 13 22:22:48 2011
New Revision: 1091938

URL: http://svn.apache.org/viewvc?rev=1091938&view=rev
Log:
TAP5-853: Checkpoint partial (broken) conversion of PropertyConduitSource to PlasticProxyFactory

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
      - copied, changed from r1091937, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StrategyBuilderImpl.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java?rev=1091938&r1=1091937&r2=1091938&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java Wed Apr 13 22:22:48 2011
@@ -1,4 +1,4 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 2008, 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,13 +14,14 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 
 /**
  * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
  */
-public class LiteralPropertyConduit extends BasePropertyConduit
+public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
 {
     private final Object value;
 
@@ -28,7 +29,7 @@ public class LiteralPropertyConduit exte
                                   TypeCoercer typeCoercer,
                                   Object value)
     {
-        super(propertyType, null, annotationProvider, description, typeCoercer);
+        super(propertyType, null, annotationProvider, typeCoercer);
 
         this.value = value;
     }

Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java (from r1091937, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java&r1=1091937&r2=1091938&rev=1091938&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java Wed Apr 13 22:22:48 2011
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
+// Copyright 2007, 2008, 2009, 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.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,42 +23,33 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 
 /**
- * Base class for {@link org.apache.tapestry5.PropertyConduit} instances created by the {@link
- * org.apache.tapestry5.services.PropertyConduitSource}.
+ * Base class for {@link org.apache.tapestry5.PropertyConduit} instances created by the
+ * {@link org.apache.tapestry5.services.PropertyConduitSource}.
  */
 @SuppressWarnings("all")
-public abstract class BasePropertyConduit implements InternalPropertyConduit
+public class PropertyConduitDelegate
 {
     private final Class propertyType;
-    
+
     private final String propertyName;
 
     private final AnnotationProvider annotationProvider;
 
-    private final String description;
-
     private final TypeCoercer typeCoercer;
 
-    public BasePropertyConduit(Class propertyType, String propertyName, AnnotationProvider annotationProvider, String description,
-                               TypeCoercer typeCoercer)
+    public PropertyConduitDelegate(Class propertyType, String propertyName, AnnotationProvider annotationProvider,
+            TypeCoercer typeCoercer)
     {
         assert propertyType != null;
         assert annotationProvider != null;
         assert typeCoercer != null;
-        assert InternalUtils.isNonBlank(description);
+
         this.propertyType = propertyType;
         this.propertyName = propertyName;
         this.annotationProvider = annotationProvider;
-        this.description = description;
         this.typeCoercer = typeCoercer;
     }
 
-    @Override
-    public final String toString()
-    {
-        return description;
-    }
-
     public final <T extends Annotation> T getAnnotation(Class<T> annotationClass)
     {
         return annotationProvider.getAnnotation(annotationClass);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=1091938&r1=1091937&r2=1091938&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java Wed Apr 13 22:22:48 2011
@@ -14,10 +14,38 @@
 
 package org.apache.tapestry5.internal.services;
 
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.DECIMAL;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.DEREF;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.FALSE;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.IDENTIFIER;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.INTEGER;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.INVOKE;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.LIST;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.NOT;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.NULL;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.RANGEOP;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.SAFEDEREF;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.STRING;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.THIS;
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.TRUE;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
 import org.antlr.runtime.ANTLRInputStream;
 import org.antlr.runtime.CommonTokenStream;
 import org.antlr.runtime.tree.Tree;
 import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
 import org.apache.tapestry5.internal.util.IntegerRange;
@@ -27,53 +55,85 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.services.ClassFab;
+import org.apache.tapestry5.ioc.services.ClassFabUtils;
+import org.apache.tapestry5.ioc.services.ClassFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.MethodSignature;
+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.TypeCoercer;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.BodyBuilder;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
+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;
+import org.apache.tapestry5.plastic.PlasticUtils;
 import org.apache.tapestry5.services.ComponentLayer;
 import org.apache.tapestry5.services.InvalidationListener;
 import org.apache.tapestry5.services.PropertyConduitSource;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
-
 public class PropertyConduitSourceImpl implements PropertyConduitSource, InvalidationListener
 {
+    private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
+
+    private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
+            Object.class);
+
     private static final MethodSignature GET_SIGNATURE = new MethodSignature(Object.class, "get", new Class[]
     { Object.class }, null);
 
     private static final MethodSignature SET_SIGNATURE = new MethodSignature(void.class, "set", new Class[]
     { Object.class, Object.class }, null);
 
-    private static final Method RANGE;
+    private static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
+
+    private static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
+
+    private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
+            "getAnnotation", Class.class);
+
+    private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
+            "getPropertyType");
+
+    private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
+            "getPropertyName");
+
+    private static final InstructionBuilderCallback RETURN_RESULT = new InstructionBuilderCallback()
+    {
+        public void doBuild(InstructionBuilder builder)
+        {
+            builder.returnResult();
+        }
+    };
 
-    private static final Method INVERT;
+    private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
+    { Object.class.getName() };
 
-    static
+    @SuppressWarnings("unchecked")
+    private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
     {
         try
         {
-            RANGE = BasePropertyConduit.class.getMethod("range", int.class, int.class);
-            INVERT = BasePropertyConduit.class.getMethod("invert", Object.class);
+            return containingClass.getMethod(name, parameterTypes);
         }
         catch (NoSuchMethodException ex)
         {
-            throw new RuntimeException(ex);
+            throw new IllegalArgumentException(ex);
         }
     }
 
+    private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
+    {
+        return new MethodDescription(getMethod(containingClass, name, parameterTypes));
+    }
+
     private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
 
     private static class ConstructorParameter
@@ -201,10 +261,25 @@ public class PropertyConduitSourceImpl i
         }
     }
 
+    private class PlasticTerm
+    {
+        final Type type;
+
+        final InstructionBuilderCallback callback;
+
+        PlasticTerm(Type type, InstructionBuilderCallback callback)
+        {
+            this.type = type;
+            this.callback = callback;
+        }
+    }
+
     private final PropertyAccess access;
 
     private final ClassFactory classFactory;
 
+    private final PlasticProxyFactory proxyFactory;
+
     private final TypeCoercer typeCoercer;
 
     private final StringInterner interner;
@@ -250,7 +325,7 @@ public class PropertyConduitSourceImpl i
      * Encapsulates the process of building a PropertyConduit instance from an
      * expression.
      */
-    class PropertyConduitBuilder
+    class PropertyConduitBuilder implements PlasticClassTransformer
     {
         private final Class rootType;
 
@@ -274,6 +349,12 @@ public class PropertyConduitSourceImpl i
 
         private final BodyBuilder navBuilder = new BodyBuilder();
 
+        private PlasticField delegateField;
+
+        private PlasticClass plasticClass;
+
+        private PlasticMethod getRootMethod, navMethod;
+
         PropertyConduitBuilder(Class rootType, String expression, Tree tree)
         {
             this.rootType = rootType;
@@ -282,7 +363,63 @@ public class PropertyConduitSourceImpl i
 
             String name = ClassFabUtils.generateClassName("PropertyConduit");
 
-            this.classFab = classFactory.newClass(name, BasePropertyConduit.class);
+            this.classFab = classFactory.newClass(name, PropertyConduitDelegate.class);
+        }
+
+        public void transform(PlasticClass plasticClass)
+        {
+            this.plasticClass = plasticClass;
+
+            delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate");
+
+            // Create the various methods; also determine the conduit's property type, property name and identify
+            // the annotation provider.
+
+            createPlasticAccessors();
+
+            addDelegateMethods();
+
+            plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
+        }
+
+        private void addDelegateMethods()
+        {
+            PropertyConduitDelegate delegate = new PropertyConduitDelegate(conduitPropertyType, conduitPropertyName,
+                    annotationProvider, typeCoercer);
+
+            delegateField.inject(delegate);
+
+            plasticClass.introduceMethod(GET_ANNOTATION).delegateTo(delegateField);
+            plasticClass.introduceMethod(GET_PROPERTY_TYPE).delegateTo(delegateField);
+            plasticClass.introduceMethod(GET_PROPERTY_NAME).delegateTo(delegateField);
+        }
+
+        /**
+         * Creates a method that does a conversion from Object to the expected root type, with
+         * a null check.
+         */
+        private void createPlasticGetRoot()
+        {
+            getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
+                    SINGLE_OBJECT_ARGUMENT, null);
+
+            getRootMethod.changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadArgument(0).dupe(0);
+                    builder.ifNull(new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            builder.throwException(NullPointerException.class,
+                                    String.format("Root object of property expression '%s' is null.", expression));
+                        }
+                    }, null);
+
+                    builder.checkcast(rootType).returnResult();
+                }
+            });
         }
 
         PropertyConduit createInstance()
@@ -398,6 +535,59 @@ public class PropertyConduitSourceImpl i
             builder.addln("%s root = getRoot($1);", ClassFabUtils.toJavaClassName(rootType));
         }
 
+        private void createPlasticAccessors()
+        {
+            createPlasticGetRoot();
+
+            // First, create the navigate method.
+
+            final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
+
+            Type activeType = rootType;
+
+            Tree node = tree;
+
+            while (!isLeaf(node))
+            {
+                PlasticTerm term = analyzeDerefNode(activeType, node);
+
+                callbacks.add(term.callback);
+
+                activeType = term.type;
+
+                // Second term is the continuation, possibly another chained
+                // DEREF, etc.
+                node = node.getChild(1);
+            }
+
+            // TODO: Optimization -- navigate method not needed (i.e., same as getRoot) for simple
+            // expressions.
+
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
+                    SINGLE_OBJECT_ARGUMENT, null);
+
+            navMethod.changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+
+                    for (InstructionBuilderCallback callback : callbacks)
+                    {
+                        callback.doBuild(builder);
+                    }
+
+                    // No need to box, the callbacks for each property ensure that primitives are boxed
+
+                    builder.returnResult();
+                }
+            });
+
+            createPlasticGetterAndSetter(activeClass, node);
+        }
+
         private void createAccessors()
         {
             createGetRoot();
@@ -435,6 +625,65 @@ public class PropertyConduitSourceImpl i
             createGetterAndSetter(activeClass, sig, node);
         }
 
+        private void createPlasticGetterAndSetter(Class activeType, Tree node)
+        {
+            switch (node.getType())
+            {
+                case IDENTIFIER:
+                case INVOKE:
+
+                    // So, a this point, we have the navigation method written
+                    // and it covers all but the terminal
+                    // de-reference. node is an IDENTIFIER or INVOKE. We're
+                    // ready to use the navigation
+                    // method to implement get() and set().
+
+                    ExpressionTermInfo info = infoForMember(activeType, node);
+
+                    createPlasticSetter(activeType, info);
+                    createPlasticGetter(activeType, info);
+
+                    conduitPropertyType = GenericsUtils.asClass(info.getType());
+                    conduitPropertyName = info.getPropertyName();
+                    annotationProvider = info;
+
+                    return;
+
+                case RANGEOP:
+
+                    // As currently implemented, RANGEOP can only appear as the
+                    // top level, which
+                    // means we didn't need the navigate method after all.
+
+                    // createPlasticRangeOpGetter(node, "root");
+                    createPlasticNoOpSetter();
+
+                    conduitPropertyType = IntegerRange.class;
+
+                    return;
+
+                case LIST:
+
+                    // createPlasticListGetter(node, "root");
+                    createPlasticNoOpSetter();
+
+                    conduitPropertyType = List.class;
+
+                    return;
+
+                case NOT:
+                    // createPlasticNotOpGetter(node);
+                    createPlasticNoOpSetter();
+
+                    conduitPropertyType = boolean.class;
+
+                    return;
+
+                default:
+                    throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
+            }
+        }
+
         private void createGetterAndSetter(Class activeType, MethodSignature navigateMethod, Tree node)
         {
             switch (node.getType())
@@ -507,6 +756,11 @@ public class PropertyConduitSourceImpl i
             classFab.addMethod(Modifier.PUBLIC, GET_SIGNATURE, builder.toString());
         }
 
+        private void createPlasticNotOpGetter()
+        {
+
+        }
+
         private void createNotOpGetter(Tree node, String rootName)
         {
             BodyBuilder builder = new BodyBuilder().begin();
@@ -564,7 +818,7 @@ public class PropertyConduitSourceImpl i
         /**
          * Evalutates the node as a sub expression, storing the result into a
          * new variable, whose name is returned.
-         *
+         * 
          * @param builder
          *            to receive generated code
          * @param node
@@ -648,7 +902,7 @@ public class PropertyConduitSourceImpl i
 
                         previousReference = generated.termReference;
                         activeType = GenericsUtils.asClass(generated.type);
-                        if ( activeType.isPrimitive() )
+                        if (activeType.isPrimitive())
                             activeType = ClassFabUtils.getWrapperType(activeType);
                         node = null;
 
@@ -681,6 +935,38 @@ public class PropertyConduitSourceImpl i
             return new GeneratedTerm(activeType, previousReference);
         }
 
+        private void createPlasticSetter(final Class activeType, final ExpressionTermInfo info)
+        {
+            final Method method = info.getWriteMethod();
+
+            if (method == null && !info.isField())
+            {
+                createPlasticNoOpSetter();
+                return;
+            }
+
+            plasticClass.introduceMethod(SET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+                    String typeName = PlasticUtils.toTypeName(GenericsUtils.asClass(info.getType()));
+
+                    builder.loadArgument(0).unboxPrimitive(typeName);
+
+                    if (info.isField())
+                    {
+                        builder.putField(PlasticUtils.toTypeName(activeType), info.getField().getName(), typeName);
+                    }
+                    else
+                    {
+                        invokeNoArgsMethod(builder, method);
+                    }
+                }
+            });
+        }
+
         private void createSetter(MethodSignature navigateMethod, ExpressionTermInfo info)
         {
             // A write method will only be identified if the info is a writable
@@ -726,12 +1012,82 @@ public class PropertyConduitSourceImpl i
             classFab.addMethod(Modifier.PUBLIC, SET_SIGNATURE, builder.toString());
         }
 
+        private void createPlasticNoOpSetter()
+        {
+            createNoOpMethod(SET, "Expression '%s' for class %s is read-only.", expression, rootType.getName());
+        }
+
+        public void createNoOpMethod(MethodDescription method, String format, Object... arguments)
+        {
+            final String message = String.format(format, arguments);
+
+            plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.throwException(RuntimeException.class, message);
+                }
+            });
+        }
+
         private void createNoOpSetter()
         {
             createNoOp(classFab, SET_SIGNATURE, "Expression '%s' for class %s is read-only.", expression,
                     rootType.getName());
         }
 
+        /**
+         * Creates the get() method, using the navigate method.
+         * 
+         * @param activeType
+         *            the type containing the property to read (may be the root type for simple
+         *            property expressions)
+         * @param info
+         *            describes the property to read
+         */
+        private void createPlasticGetter(final Class activeType, final ExpressionTermInfo info)
+        {
+            final Method method = info.getReadMethod();
+
+            if (method == null && !info.isField())
+            {
+                createNoOpMethod(GET, "Expression %s for class %s is write-only.", expression, rootType.getName());
+                return;
+            }
+
+            plasticClass.introduceMethod(GET).changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+                    // I.e. due to ?. operator. The navigate method will already have
+                    // checked for nulls if they are not allowed.
+
+                    builder.dupe(0).ifNull(RETURN_RESULT, null);
+
+                    Class termType = GenericsUtils.asClass(info.getType());
+                    String termTypeName = PlasticUtils.toTypeName(termType);
+
+                    if (info.isField())
+                    {
+                        builder.getField(PlasticUtils.toTypeName(activeType), info.getPropertyName(), termTypeName);
+                    }
+                    else
+                    {
+                        invokeNoArgsMethod(builder, method);
+                    }
+
+                    builder.boxPrimitive(termTypeName).returnResult();
+                }
+            });
+        }
+
+        private void invokeNoArgsMethod(InstructionBuilder builder, Method method)
+        {
+            builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName());
+        }
+
         private void createGetter(MethodSignature navigateMethod, Tree node, ExpressionTermInfo info)
         {
             Method method = info.getReadMethod();
@@ -767,7 +1123,7 @@ public class PropertyConduitSourceImpl i
 
         /**
          * Creates a method invocation call for the given node (an INVOKE node).
-         *
+         * 
          * @param bodyBuilder
          *            may receive new code to define variables for some
          *            sub-expressions
@@ -791,7 +1147,7 @@ public class PropertyConduitSourceImpl i
 
         /**
          * Creates a method invocation call for the given node
-         *
+         * 
          * @param bodyBuilder
          *            may receive new code to define variables for some
          *            sub-expressions
@@ -870,6 +1226,24 @@ public class PropertyConduitSourceImpl i
         /**
          * Extends the navigate method for a node, which will be a DEREF or
          * SAFEDERF.
+         * 
+         * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
+         *         to advance the evaluation of the expression form the previous value to the current
+         */
+        private PlasticTerm analyzeDerefNode(Type activeType, Tree node)
+        {
+            // The first child is the term.
+
+            Tree term = node.getChild(0);
+
+            boolean allowNull = node.getType() == SAFEDEREF;
+
+            return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
+        }
+
+        /**
+         * Extends the navigate method for a node, which will be a DEREF or
+         * SAFEDERF.
          */
         private GeneratedTerm processDerefNode(BodyBuilder builder, Type activeType, Tree node,
                 String previousVariableName, String rootName)
@@ -911,6 +1285,82 @@ public class PropertyConduitSourceImpl i
             return InternalUtils.lastTerm(type.getName());
         }
 
+        private PlasticTerm buildTerm(Type activeType, final Tree term, final NullHandling nullHandling)
+        {
+            assertNodeType(term, IDENTIFIER, INVOKE);
+
+            // Get info about this property or method.
+
+            final ExpressionTermInfo info = infoForMember(activeType, term);
+
+            final Method method = info.getReadMethod();
+            final Class activeClass = GenericsUtils.asClass(activeType);
+
+            if (method == null && !info.isField())
+                throw new RuntimeException(String.format(
+                        "Property '%s' of class %s is not readable (it has no read accessor method).",
+                        info.getDescription(), activeClass.getName()));
+
+            Type termType = info.getType();
+
+            final Class termClass = GenericsUtils.asClass(termType);
+
+            final Class wrappedType = ClassFabUtils.getWrapperType(termClass);
+
+            String wrapperTypeName = ClassFabUtils.toJavaClassName(wrappedType);
+
+            final String variableName = nextVariableName(wrappedType);
+
+            InstructionBuilderCallback callback = new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    if (info.isField())
+                    {
+                        String typeName = PlasticUtils.toTypeName(termClass);
+
+                        builder.getField(PlasticUtils.toTypeName(info.getField().getDeclaringClass()), info.getField()
+                                .getName(), typeName);
+
+                        builder.unboxPrimitive(typeName);
+                    }
+                    else
+                    {
+                        createPlasticMethodInvocation(term, method);
+                    }
+
+                    builder.dupe(0).ifNull(new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            switch (nullHandling)
+                            {
+                                case ALLOW:
+                                    builder.returnResult();
+
+                                case FORBID:
+
+                                    builder.loadConstant(info.getDescription());
+                                    builder.loadConstant(expression);
+                                    builder.loadArgument(0);
+
+                                    builder.invokeStatic(PropertyConduitSourceImpl.class, void.class, "nullTerm",
+                                            String.class, String.class, Object.class);
+                            }
+                        }
+                    }, null);
+                }
+            };
+
+            return new PlasticTerm(termType, callback);
+        }
+
+        private void createPlasticMethodInvocation(Tree term, Method method)
+        {
+            // TODO Auto-generated method stub
+
+        }
+
         private GeneratedTerm addAccessForMember(BodyBuilder builder, Type activeType, Tree term,
                 String previousVariableName, String rootName, NullHandling nullHandling)
         {
@@ -949,7 +1399,7 @@ public class PropertyConduitSourceImpl i
             {
                 builder.add(" ($w) ");
             }
-            else if (info.isCastRequired() )
+            else if (info.isCastRequired())
             {
                 builder.add(" (%s) ", wrapperTypeName);
             }
@@ -1161,8 +1611,8 @@ public class PropertyConduitSourceImpl i
             }
             catch (NoSuchMethodException ex)
             {
-                throw new RuntimeException(
-                        String.format("No public method '%s()' in class %s.", methodName, activeClass.getName()));
+                throw new RuntimeException(String.format("No public method '%s()' in class %s.", methodName,
+                        activeClass.getName()));
             }
         }
 
@@ -1185,10 +1635,12 @@ public class PropertyConduitSourceImpl i
     }
 
     public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
-    ClassFactory classFactory, TypeCoercer typeCoercer, StringInterner interner)
+    ClassFactory classFactory, @ComponentLayer
+    PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
     {
         this.access = access;
         this.classFactory = classFactory;
+        this.proxyFactory = proxyFactory;
         this.typeCoercer = typeCoercer;
         this.interner = interner;
 
@@ -1244,13 +1696,13 @@ public class PropertyConduitSourceImpl i
     }
 
     /**
-     * Builds a subclass of {@link BasePropertyConduit} that implements the
+     * Builds a subclass of {@link PropertyConduitDelegate} that implements the
      * get() and set() methods and overrides the
      * constructor. In a worst-case race condition, we may build two (or more)
      * conduits for the same
      * rootClass/expression, and it will get sorted out when the conduit is
      * stored into the cache.
-     *
+     * 
      * @param rootClass
      *            class of root object for expression evaluation
      * @param expression
@@ -1322,7 +1774,8 @@ public class PropertyConduitSourceImpl i
                     break;
             }
 
-            return new PropertyConduitBuilder(rootClass, expression, tree).createInstance();
+            return proxyFactory.createProxy(InternalPropertyConduit.class,
+                    new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
         }
         catch (Exception ex)
         {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java?rev=1091938&r1=1091937&r2=1091938&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java Wed Apr 13 22:22:48 2011
@@ -51,7 +51,7 @@ public class PlasticProxyFactoryImpl imp
         return manager.getClassLoader();
     }
 
-    public ClassInstantiator createProxy(Class interfaceType, PlasticClassTransformer callback)
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
     {
         return manager.createProxy(interfaceType, callback);
     }
@@ -67,7 +67,7 @@ public class PlasticProxyFactoryImpl imp
         assert creator != null;
         assert InternalUtils.isNonBlank(description);
 
-        ClassInstantiator instantiator = createProxy(interfaceType, new PlasticClassTransformer()
+        ClassInstantiator<T> instantiator = createProxy(interfaceType, new PlasticClassTransformer()
         {
             public void transform(PlasticClass plasticClass)
             {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StrategyBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StrategyBuilderImpl.java?rev=1091938&r1=1091937&r2=1091938&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StrategyBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StrategyBuilderImpl.java Wed Apr 13 22:22:48 2011
@@ -24,10 +24,10 @@ import org.apache.tapestry5.ioc.util.Str
 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.PlasticUtils;
 
 public class StrategyBuilderImpl implements StrategyBuilder
 {
@@ -62,7 +62,7 @@ public class StrategyBuilderImpl impleme
 
                 for (final Method method : interfaceType.getMethods())
                 {
-                    plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+                    plasticClass.introduceMethod(new MethodDescription(method), new InstructionBuilderCallback()
                     {
                         public void doBuild(InstructionBuilder builder)
                         {