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/03/29 19:24:35 UTC

svn commit: r1086644 [1/5] - in /tapestry/tapestry5/trunk: ./ plastic/ plastic/src/ plastic/src/main/ plastic/src/main/java/ plastic/src/main/java/org/ plastic/src/main/java/org/apache/ plastic/src/main/java/org/apache/tapestry5/ plastic/src/main/java/...

Author: hlship
Date: Tue Mar 29 17:24:31 2011
New Revision: 1086644

URL: http://svn.apache.org/viewvc?rev=1086644&view=rev
Log:
Initial import of Plastic as a Tapestry sub-project

Added:
    tapestry/tapestry5/trunk/plastic/
    tapestry/tapestry5/trunk/plastic/build.gradle
    tapestry/tapestry5/trunk/plastic/src/
    tapestry/tapestry5/trunk/plastic/src/main/
    tapestry/tapestry5/trunk/plastic/src/main/java/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractAnnotationBuilder.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractMethodInvocation.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AnnotationBuilder.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Cache.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassInstantiatorImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassLoaderDelegate.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/EmptyAnnotationAccess.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FailureMethodInvocationResult.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldHandleImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldState.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderState.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/LocalVariable.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodHandleImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NameCache.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NoopDelegate.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassHandleShim.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassLoader.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassTransformation.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticInternalUtils.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PrimitiveType.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/StandardDelegate.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/StaticContext.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/SuccessMethodInvocationResult.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/SwitchBlockImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/TryCatchBlockImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/TypeCategory.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/AnnotationAccess.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassInstantiator.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ComputedValue.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/FieldConduit.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/FieldHandle.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstanceContext.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilder.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/InstructionBuilderCallback.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodAdvice.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodDescription.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodHandle.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodInvocation.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodInvocationResult.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/MethodParameter.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/Opcodes.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClassTransformer.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticField.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManagerDelegate.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticMethod.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticUtils.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PropertyAccessType.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/SwitchBlock.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/SwitchCallback.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/TryCatchBlock.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/TryCatchCallback.java
    tapestry/tapestry5/trunk/plastic/src/test/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/internal/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/internal/plastic/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/internal/plastic/ClassInstantiatorTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/internal/plastic/PlasticUtilsTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AbstractPlasticSpecification.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ArrayAttributeAnnotations.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ClassAnnotationAccess.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAnnotationAccess.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldClaiming.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldHandleTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldInjection.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/IntroduceFieldTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAdviceTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAnnotationAccess.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodHandleAccess.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodImplementationTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodProxying.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ObtainPlasticClass.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ParameterAnnotationsTest.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/SimpleClassLoading.groovy
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ToStringTests.groovy
    tapestry/tapestry5/trunk/plastic/src/test/java/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/tapestry5/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/tapestry5/plastic/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/tapestry5/plastic/test/
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/tapestry5/plastic/test/NoopAdvice.java
    tapestry/tapestry5/trunk/plastic/src/test/java/org/apache/tapestry5/plastic/test/TestInject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AlternateConstructor.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ArrayAnnotation.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ArrayAttributesSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/BaseClass.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ChildClass.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ContextCatcher.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/CreateAccessorsSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Empty.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ExplicityEmptyArrayAttributesSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/HasToString.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/InjectFieldSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/InjectionSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/InjectionSubjectSubclass.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/IntFieldHolder.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/LongFieldHolder.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Maybe.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Memory.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MethodAdviceTarget.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MethodHandleSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MethodReimplementationSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MiddleClass.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MultipleFields.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/MultipleMethods.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/NonPrivateInstanceField.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Outer.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ParameterAnnotationsSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/PrimitiveValues.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Property.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ScratchPad.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/SimpleAnnotation.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/SingleField.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/SingleMethod.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticFields.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StaticMethodsIgnored.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StringHolder.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/StringPropertyHolder.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/TestInjectTransformer.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/Truth.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/WillNotDoubleException.java
Modified:
    tapestry/tapestry5/trunk/settings.gradle

Added: tapestry/tapestry5/trunk/plastic/build.gradle
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/build.gradle?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/build.gradle (added)
+++ tapestry/tapestry5/trunk/plastic/build.gradle Tue Mar 29 17:24:31 2011
@@ -0,0 +1,11 @@
+description = "Plastic core framework"
+
+dependencies {
+	compile "asm:asm-all:3.3.1"
+    
+	testCompile "org.spockframework:spock-core:0.5-groovy-1.7"    
+}
+
+test {
+	useJUnit()
+}
\ No newline at end of file

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractAnnotationBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractAnnotationBuilder.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractAnnotationBuilder.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractAnnotationBuilder.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,140 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+
+@SuppressWarnings(
+{ "rawtypes", "unchecked" })
+public abstract class AbstractAnnotationBuilder implements AnnotationVisitor
+{
+    protected final PlasticClassPool pool;
+
+    public AbstractAnnotationBuilder(PlasticClassPool pool)
+    {
+        this.pool = pool;
+    }
+
+    protected abstract void store(String name, Object value);
+
+    protected Class elementTypeForArrayAttribute(String name)
+    {
+        throw new IllegalStateException("elementTypeForArrayAttribute() may not be invoked here.");
+    }
+
+    public void visit(String name, Object value)
+    {
+        if (value instanceof Type)
+        {
+            Type type = (Type) value;
+
+            Class valueType = pool.loadClass(type.getClassName());
+            store(name, valueType);
+            return;
+        }
+
+        store(name, value);
+    }
+
+    public void visitEnum(String name, String desc, String value)
+    {
+
+        try
+        {
+            String enumClassName = PlasticInternalUtils.objectDescriptorToClassName(desc);
+
+            Class enumClass = pool.loader.loadClass(enumClassName);
+
+            Object enumValue = Enum.valueOf(enumClass, value);
+
+            store(name, enumValue);
+        }
+        catch (Exception ex)
+        {
+            throw new IllegalArgumentException(String.format("Unable to convert enum annotation attribute %s %s: %s",
+                    value, desc, PlasticInternalUtils.toMessage(ex)), ex);
+        }
+    }
+
+    public AnnotationVisitor visitAnnotation(final String name, String desc)
+    {
+        final AbstractAnnotationBuilder outerBuilder = this;
+
+        final Class nestedAnnotationType = pool.loadClass(PlasticInternalUtils.objectDescriptorToClassName(desc));
+
+        // Return a nested builder that constructs the inner annotation and, at the end of
+        // construction, pushes the final Annotation object into this builder's attributes.
+
+        return new AnnotationBuilder(nestedAnnotationType, pool)
+        {
+            @Override
+            public void visitEnd()
+            {
+                outerBuilder.store(name, createAnnotation());
+            };
+        };
+    }
+
+    /**
+     * Because of how ASM works, this should only be invoked when the array values are not
+     * primitives and not Class/Type; i.e. the inner values will be either Class/Type, enum, or
+     * nested annotations. All the arrays of strings and primitives are handled by ASM and become
+     * a single call to {@link #visit(String, Object)}.
+     */
+    public AnnotationVisitor visitArray(final String name)
+    {
+        final List<Object> values = new ArrayList<Object>();
+
+        final Class componentType = elementTypeForArrayAttribute(name);
+
+        final AbstractAnnotationBuilder outerBuilder = this;
+
+        return new AbstractAnnotationBuilder(pool)
+        {
+            @Override
+            protected void store(String name, Object value)
+            {
+                values.add(value);
+            }
+
+            @Override
+            public void visitEnd()
+            {
+                Object array = Array.newInstance(componentType, values.size());
+
+                // Now, empty arrays may be primitive types and will not cast to Object[], but
+                // non empty arrays indicate that it was a Class/Enum/Annotation, which can cast
+                // to Object[]
+
+                if (values.size() != 0)
+                    array = values.toArray((Object[]) array);
+
+                outerBuilder.store(name, array);
+            }
+        };
+    }
+
+    public void visitEnd()
+    {
+        // Nothing to do here. Subclasses use this as a chance to store a value into an outer
+        // builder.
+    }
+
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractMethodInvocation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractMethodInvocation.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractMethodInvocation.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AbstractMethodInvocation.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,89 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.InstanceContext;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodInvocation;
+
+public abstract class AbstractMethodInvocation implements MethodInvocation
+{
+    private final Object instance;
+
+    private final InstanceContext instanceContext;
+
+    private final MethodAdvice[] advice;
+
+    private int adviceIndex;
+
+    protected AbstractMethodInvocation(Object instance, InstanceContext instanceContext, MethodAdvice[] advice)
+    {
+        this.instance = instance;
+        this.instanceContext = instanceContext;
+        this.advice = advice;
+    }
+
+    private Exception checkedException;
+
+    public void rethrow()
+    {
+        if (checkedException != null)
+            throw new RuntimeException(checkedException);
+    }
+
+    public boolean didThrowCheckedException()
+    {
+        return checkedException != null;
+    }
+
+    public <T extends Throwable> T getCheckedException(Class<T> exceptionType)
+    {
+        assert exceptionType != null;
+
+        if (exceptionType.isInstance(checkedException))
+            return exceptionType.cast(checkedException);
+
+        return null;
+    }
+
+    public Object getInstance()
+    {
+        return instance;
+    }
+
+    public InstanceContext getInstanceContext()
+    {
+        return instanceContext;
+    }
+
+    public MethodInvocation proceed()
+    {
+        if (adviceIndex == advice.length)
+            proceedToAdvisedMethod();
+        else
+            advice[adviceIndex++].advise(this);
+
+        return this;
+    }
+
+    public MethodInvocation setCheckedException(Exception exception)
+    {
+        checkedException = exception;
+
+        return this;
+    }
+
+    protected abstract void proceedToAdvisedMethod();
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AnnotationBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AnnotationBuilder.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AnnotationBuilder.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/AnnotationBuilder.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,118 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+
+@SuppressWarnings(
+{ "rawtypes", "unchecked" })
+public class AnnotationBuilder extends AbstractAnnotationBuilder
+{
+    private static final class AnnotationValueHandler implements InvocationHandler
+    {
+        private final Class annotationType;
+
+        private final Map<String, Object> attributes;
+
+        public AnnotationValueHandler(final Class annotationType, Map<String, Object> attributes)
+        {
+            this.annotationType = annotationType;
+            this.attributes = attributes;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+        {
+            // args is null for no-arguments methods
+            if (args == null)
+            {
+                String attributeName = method.getName();
+
+                if (attributes.containsKey(attributeName)) { return attributes.get(attributeName); }
+            }
+
+            // TODO: Handling of equals() and hashCode() and toString(), plus other methods
+            // inherited from Object
+
+            throw new RuntimeException(String.format("Annotation proxy for class %s does not handle method %s.",
+                    annotationType.getName(), method));
+        }
+    }
+
+    private final Class annotationType;
+
+    final Map<String, Object> attributes = PlasticInternalUtils.newMap();
+
+    public AnnotationBuilder(Class annotationType, PlasticClassPool pool)
+    {
+        super(pool);
+
+        this.annotationType = annotationType;
+
+        attributes.put("annotationType", annotationType);
+
+        // Annotation attributes are represented as methods, and for each method there may be a
+        // default value. Preload the default values, which may be overwritten by explicit
+        // values.
+
+        for (Method m : annotationType.getMethods())
+        {
+            Object defaultValue = m.getDefaultValue();
+
+            if (defaultValue != null)
+                attributes.put(m.getName(), defaultValue);
+        }
+    }
+
+    protected void store(String name, Object value)
+    {
+        attributes.put(name, value);
+    }
+
+    protected Class elementTypeForArrayAttribute(String name)
+    {
+        try
+        {
+            return annotationType.getMethod(name).getReturnType().getComponentType();
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(String.format(
+                    "Unable to determine element type for attribute '%s' of annotation %s: %s", name,
+                    annotationType.getName(), PlasticInternalUtils.toMessage(ex)), ex);
+        }
+    }
+
+    public Object createAnnotation()
+    {
+        // Use a static inner class to keep the AnnotationBuilder from being retained
+
+        InvocationHandler handler = new AnnotationValueHandler(annotationType, attributes);
+
+        try
+        {
+            return Proxy.newProxyInstance(pool.loader, new Class[]
+            { annotationType }, handler);
+        }
+        catch (IllegalArgumentException ex)
+        {
+            throw new IllegalArgumentException(String.format("Unable to create instance of annotation type %s: %s",
+                    annotationType.getName(), PlasticInternalUtils.toMessage(ex)), ex);
+        }
+    }
+
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Cache.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Cache.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Cache.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Cache.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,45 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Quick and dirty key/value cache that is subclassed to provide the logic that generates the value for
+ * a missing key.
+ * 
+ * @param <S>
+ * @param <T>
+ */
+public abstract class Cache<S, T>
+{
+    private Map<S, T> innerCache = new HashMap<S, T>();
+
+    public T get(S input)
+    {
+        T result = innerCache.get(input);
+
+        if (result == null)
+        {
+            result = convert(input);
+            innerCache.put(input, result);
+        }
+
+        return result;
+    }
+
+    protected abstract T convert(S input);
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassInstantiatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassInstantiatorImpl.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassInstantiatorImpl.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassInstantiatorImpl.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,107 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.InstanceContext;
+
+@SuppressWarnings("all")
+public class ClassInstantiatorImpl implements ClassInstantiator, InstanceContext
+{
+    private final Class clazz;
+
+    private final Constructor ctor;
+
+    private final StaticContext staticContext;
+
+    // Keeping a whole HashMap around for just one or two values feels wasteful, perhaps
+    // come up with something else later.
+
+    private final Map instanceContextMap;
+
+    ClassInstantiatorImpl(Class clazz, Constructor ctor, StaticContext staticContext)
+    {
+        this(clazz, ctor, staticContext, null);
+    }
+
+    private ClassInstantiatorImpl(Class clazz, Constructor ctor, StaticContext staticContext, Map instanceContextMap)
+    {
+        this.clazz = clazz;
+        this.ctor = ctor;
+        this.staticContext = staticContext;
+        this.instanceContextMap = instanceContextMap;
+    }
+
+    public <T> ClassInstantiator with(Class<T> valueType, T instanceContextValue)
+    {
+        assert valueType != null;
+        assert instanceContextValue != null;
+
+        Object existing = getFromMap(valueType);
+
+        if (existing != null)
+            throw new IllegalStateException(String.format(
+                    "An instance context value of type %s has already been added.", valueType.getName()));
+
+        Map newMap = instanceContextMap == null ? new HashMap() : new HashMap(instanceContextMap);
+
+        newMap.put(valueType, instanceContextValue);
+
+        return new ClassInstantiatorImpl(clazz, ctor, staticContext, newMap);
+    }
+
+    public <T> T get(Class<T> valueType)
+    {
+        T result = getFromMap(valueType);
+
+        if (result == null)
+            throw new IllegalArgumentException(String.format(
+                    "Instance context for class %s does not contain a value for type %s.", clazz.getName(), valueType));
+
+        return result;
+    }
+
+    private <T> T getFromMap(Class<T> valueType)
+    {
+        return instanceContextMap == null ? null : valueType.cast(instanceContextMap.get(valueType));
+    }
+
+    public Object newInstance()
+    {
+        try
+        {
+            return ctor.newInstance(staticContext, this);
+        }
+        catch (Throwable ex)
+        {
+            throw new RuntimeException(String.format("Unable to instantiate instance of transformed class %s: %s",
+                    clazz.getName(), PlasticInternalUtils.toMessage(ex)), ex);
+        }
+    }
+
+    public Class<?> getInstanceType()
+    {
+        return clazz;
+    }
+
+    public String toString()
+    {
+        return String.format("ClassInstantiator[%s]", clazz.getName());
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassLoaderDelegate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassLoaderDelegate.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassLoaderDelegate.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/ClassLoaderDelegate.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,41 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+/**
+ * Externalizes the logic for defining which classes will be loaded (and possibly transformed) by the class loader, and
+ * which will be loaded by the parent class loader.
+ */
+public interface ClassLoaderDelegate
+{
+    /**
+     * Identifies which classes are to be loaded.
+     * 
+     * @param className
+     *            fully qualified class name
+     * @return true if the class should be intercepted, false to let parent class loader load class
+     */
+    boolean shouldInterceptClassLoading(String className);
+
+    /**
+     * Load the class, transforming it as necessary.
+     * 
+     * @param className
+     *            binary class name
+     * @return loaded and (if not an inner class) transformed class
+     * @throws ClassNotFoundException
+     */
+    Class<?> loadAndTransformClass(String className) throws ClassNotFoundException;
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/EmptyAnnotationAccess.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/EmptyAnnotationAccess.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/EmptyAnnotationAccess.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/EmptyAnnotationAccess.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,38 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.tapestry5.plastic.AnnotationAccess;
+
+public class EmptyAnnotationAccess implements AnnotationAccess
+{
+    public static final AnnotationAccess SINGLETON = new EmptyAnnotationAccess();
+
+    private EmptyAnnotationAccess()
+    {
+    }
+
+    public <T extends Annotation> boolean hasAnnotation(Class<T> annotationType)
+    {
+        return false;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType)
+    {
+        return null;
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FailureMethodInvocationResult.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FailureMethodInvocationResult.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FailureMethodInvocationResult.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FailureMethodInvocationResult.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,53 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.MethodInvocationResult;
+
+public class FailureMethodInvocationResult implements MethodInvocationResult
+{
+    private final Throwable thrown;
+
+    public FailureMethodInvocationResult(Throwable thrown)
+    {
+        assert thrown != null;
+
+        this.thrown = thrown;
+    }
+
+    public Object getReturnValue()
+    {
+        return null;
+    }
+
+    public void rethrow()
+    {
+        throw new RuntimeException(thrown);
+    }
+
+    public boolean didThrowCheckedException()
+    {
+        return true;
+    }
+
+    public <T extends Throwable> T getCheckedException(Class<T> exceptionType)
+    {
+        if (exceptionType.isInstance(thrown))
+            return exceptionType.cast(thrown);
+
+        return null;
+    }
+
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldHandleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldHandleImpl.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldHandleImpl.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldHandleImpl.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,61 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.FieldHandle;
+
+public class FieldHandleImpl implements FieldHandle
+{
+    private final String className, fieldName;
+
+    private final int fieldIndex;
+
+    protected volatile PlasticClassHandleShim shim;
+
+    public FieldHandleImpl(String className, String fieldName, int fieldIndex)
+    {
+        this.className = className;
+        this.fieldName = fieldName;
+        this.fieldIndex = fieldIndex;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("FieldHandle[%s#%s]", className, fieldName);
+    }
+
+    public Object get(Object instance)
+    {
+        checkNullInstance(instance, "get");
+
+        return shim.get(instance, fieldIndex);
+    }
+
+    private void checkNullInstance(Object instance, String action)
+    {
+        if (instance == null)
+            throw new NullPointerException(String.format(
+                    "Unable to %s value of field %s of class %s, as provided instance is null.", action, fieldName,
+                    className));
+    }
+
+    public void set(Object instance, Object newValue)
+    {
+        checkNullInstance(instance, "set");
+
+        shim.set(instance, fieldIndex, newValue);
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldState.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldState.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldState.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldState.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,27 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+public enum FieldState
+{
+    INITIAL("in initial state"), INJECTED("has an injection"), CONDUIT("has a FieldConduit");
+
+    private FieldState(String description)
+    {
+        this.description = description;
+    }
+
+    public final String description;
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderImpl.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,574 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.InstructionBuilder;
+import org.apache.tapestry5.plastic.InstructionBuilderCallback;
+import org.apache.tapestry5.plastic.MethodDescription;
+import org.apache.tapestry5.plastic.SwitchCallback;
+import org.apache.tapestry5.plastic.TryCatchCallback;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+@SuppressWarnings("rawtypes")
+public class InstructionBuilderImpl extends Lockable implements Opcodes, InstructionBuilder
+{
+    private static final int[] DUPE_OPCODES = new int[]
+    { DUP, DUP_X1, DUP_X2 };
+
+    protected final InstructionBuilderState state;
+
+    protected final MethodVisitor v;
+
+    protected final NameCache cache;
+
+    InstructionBuilderImpl(MethodDescription description, MethodVisitor visitor, NameCache cache)
+    {
+        this(new InstructionBuilderState(description, visitor, cache));
+    }
+
+    InstructionBuilderImpl(InstructionBuilderState state)
+    {
+        this.state = state;
+
+        // These are conveniences for values stored inside the state. In fact,
+        // these fields predate the InstructionBuilderState type.
+        this.v = state.visitor;
+        this.cache = state.nameCache;
+    }
+
+    public InstructionBuilder returnDefaultValue()
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(state.description.returnType);
+
+        if (type == null)
+        {
+            v.visitInsn(ACONST_NULL);
+            v.visitInsn(ARETURN);
+        }
+        else
+        {
+            switch (type)
+            {
+                case VOID:
+                    break;
+
+                case LONG:
+                    v.visitInsn(LCONST_0);
+                    break;
+
+                case FLOAT:
+                    v.visitInsn(FCONST_0);
+                    break;
+
+                case DOUBLE:
+                    v.visitInsn(DCONST_0);
+                    break;
+
+                default:
+                    v.visitInsn(ICONST_0);
+                    break;
+            }
+
+            v.visitInsn(type.returnOpcode);
+        }
+
+        return this;
+    }
+
+    public InstructionBuilder loadThis()
+    {
+        check();
+
+        v.visitVarInsn(ALOAD, 0);
+
+        return this;
+    }
+
+    public InstructionBuilder loadNull()
+    {
+        check();
+
+        v.visitInsn(ACONST_NULL);
+
+        return this;
+    }
+
+    public InstructionBuilder loadArgument(int index)
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(state.description.argumentTypes[index]);
+
+        int opcode = type == null ? ALOAD : type.loadOpcode;
+
+        // TODO: May need to adjust offset for static (0) vs. instance (1) method.
+
+        v.visitVarInsn(opcode, index + 1);
+
+        return this;
+    }
+
+    public InstructionBuilder loadArguments()
+    {
+        check();
+
+        for (int i = 0; i < state.description.argumentTypes.length; i++)
+        {
+            loadArgument(i);
+        }
+
+        return this;
+    }
+
+    public InstructionBuilder invokeSpecial(String containingClassName, MethodDescription description)
+    {
+        check();
+
+        doInvoke(INVOKESPECIAL, containingClassName, description);
+
+        return this;
+    }
+
+    public InstructionBuilder invokeVirtual(String className, String returnType, String methodName,
+            String... argumentTypes)
+    {
+        check();
+
+        doInvoke(INVOKEVIRTUAL, className, returnType, methodName, argumentTypes);
+
+        return this;
+    }
+
+    public InstructionBuilder invokeInterface(String interfaceName, String returnType, String methodName,
+            String... argumentTypes)
+    {
+        check();
+
+        doInvoke(INVOKEINTERFACE, interfaceName, returnType, methodName, argumentTypes);
+
+        return this;
+    }
+
+    private void doInvoke(int opcode, String className, String returnType, String methodName, String... argumentTypes)
+    {
+        v.visitMethodInsn(opcode, cache.toInternalName(className), methodName,
+                cache.toMethodDescriptor(returnType, argumentTypes));
+    }
+
+    private void doInvoke(int opcode, Class clazz, Class returnType, String methodName, Class... argumentTypes)
+    {
+        doInvoke(opcode, clazz.getName(), cache.toTypeName(returnType), methodName,
+                PlasticInternalUtils.toTypeNames(argumentTypes));
+    }
+
+    public InstructionBuilder invoke(Class clazz, Class returnType, String methodName, Class... argumentTypes)
+    {
+        check();
+
+        doInvoke(clazz.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, clazz, returnType, methodName, argumentTypes);
+
+        return this;
+    }
+
+    private void doInvoke(int opcode, String containingClassName, MethodDescription description)
+    {
+        v.visitMethodInsn(opcode, cache.toInternalName(containingClassName), description.methodName,
+                cache.toDesc(description));
+    }
+
+    public InstructionBuilder returnResult()
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(state.description.returnType);
+
+        int opcode = type == null ? ARETURN : type.returnOpcode;
+
+        v.visitInsn(opcode);
+
+        return this;
+    }
+
+    public InstructionBuilder boxPrimitive(String typeName)
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(typeName);
+
+        if (type != null && type != PrimitiveType.VOID)
+        {
+            v.visitMethodInsn(INVOKESTATIC, type.wrapperInternalName, "valueOf", type.valueOfMethodDescriptor);
+        }
+
+        return this;
+    }
+
+    public InstructionBuilder unboxPrimitive(String typeName)
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(typeName);
+
+        if (type != null)
+        {
+            doUnbox(type);
+        }
+
+        return this;
+    }
+
+    private void doUnbox(PrimitiveType type)
+    {
+        v.visitMethodInsn(INVOKEVIRTUAL, type.wrapperInternalName, type.toValueMethodName, type.toValueMethodDescriptor);
+    }
+
+    public InstructionBuilder getField(String className, String fieldName, String typeName)
+    {
+        check();
+
+        v.visitFieldInsn(GETFIELD, cache.toInternalName(className), fieldName, cache.toDesc(typeName));
+
+        return this;
+    }
+
+    public InstructionBuilder putField(String className, String fieldName, String typeName)
+    {
+        check();
+
+        v.visitFieldInsn(PUTFIELD, cache.toInternalName(className), fieldName, cache.toDesc(typeName));
+
+        return this;
+    }
+
+    public InstructionBuilder putField(String className, String fieldName, Class fieldType)
+    {
+        check();
+
+        return putField(className, fieldName, cache.toTypeName(fieldType));
+    }
+
+    public InstructionBuilder getField(String className, String fieldName, Class fieldType)
+    {
+        check();
+
+        return getField(className, fieldName, fieldType.getName());
+    }
+
+    public InstructionBuilder loadArrayElement(int index, String elementType)
+    {
+        check();
+
+        v.visitLdcInsn(index);
+
+        PrimitiveType type = PrimitiveType.getByName(elementType);
+
+        if (type == null)
+        {
+            v.visitInsn(AALOAD);
+        }
+        else
+        {
+            throw new RuntimeException("Access to non-object arrays is not yet supported.");
+        }
+
+        return this;
+    }
+
+    public InstructionBuilder checkcast(String className)
+    {
+        check();
+
+        // Found out the hard way that array names are handled differently; you cast to the descriptor, not the internal
+        // name.
+
+        String internalName = className.contains("[") ? cache.toDesc(className) : cache.toInternalName(className);
+
+        v.visitTypeInsn(CHECKCAST, internalName);
+
+        return this;
+    }
+
+    public InstructionBuilder checkcast(Class clazz)
+    {
+        check();
+
+        return checkcast(cache.toTypeName(clazz));
+    }
+
+    public InstructionBuilder startTryCatch(TryCatchCallback callback)
+    {
+        check();
+
+        new TryCatchBlockImpl(state).doCallback(callback);
+
+        return this;
+    }
+
+    public InstructionBuilder newInstance(String className)
+    {
+        check();
+
+        v.visitTypeInsn(NEW, cache.toInternalName(className));
+
+        return this;
+    }
+
+    public InstructionBuilder newInstance(Class clazz)
+    {
+        check();
+
+        return newInstance(clazz.getName());
+    }
+
+    public InstructionBuilder invokeConstructor(String className, String... argumentTypes)
+    {
+        check();
+
+        doInvoke(INVOKESPECIAL, className, "void", "<init>", argumentTypes);
+
+        return this;
+    }
+
+    public InstructionBuilder invokeConstructor(Class clazz, Class... argumentTypes)
+    {
+        check();
+
+        return invokeConstructor(clazz.getName(), PlasticInternalUtils.toTypeNames(argumentTypes));
+    }
+
+    public InstructionBuilder dupe(int depth)
+    {
+        check();
+
+        if (depth < 0 || depth >= DUPE_OPCODES.length)
+            throw new IllegalArgumentException(String.format(
+                    "Dupe depth %d is invalid; values from 0 to %d are allowed.", depth, DUPE_OPCODES.length - 1));
+
+        v.visitInsn(DUPE_OPCODES[depth]);
+
+        return this;
+    }
+
+    public InstructionBuilder pop()
+    {
+        check();
+
+        v.visitInsn(POP);
+
+        return this;
+    }
+
+    public InstructionBuilder swap()
+    {
+        check();
+
+        v.visitInsn(SWAP);
+
+        return this;
+    }
+
+    public InstructionBuilder loadConstant(Object constant)
+    {
+        check();
+
+        v.visitLdcInsn(constant);
+
+        return this;
+    }
+
+    public InstructionBuilder loadTypeConstant(String typeName)
+    {
+        check();
+
+        Type type = Type.getType(cache.toDesc(typeName));
+
+        v.visitLdcInsn(type);
+
+        return this;
+    }
+
+    public InstructionBuilder loadTypeConstant(Class clazz)
+    {
+        check();
+
+        Type type = Type.getType(clazz);
+
+        v.visitLdcInsn(type);
+
+        return this;
+    }
+
+    public InstructionBuilder castOrUnbox(String typeName)
+    {
+        check();
+
+        PrimitiveType type = PrimitiveType.getByName(typeName);
+
+        if (type == null)
+            return checkcast(typeName);
+
+        v.visitTypeInsn(CHECKCAST, type.wrapperInternalName);
+        doUnbox(type);
+
+        return this;
+    }
+
+    public InstructionBuilder throwException(String className, String message)
+    {
+        check();
+
+        newInstance(className);
+        dupe(0);
+        loadConstant(message);
+        invokeConstructor(className, "java.lang.String");
+        v.visitInsn(ATHROW);
+
+        return this;
+    }
+
+    public InstructionBuilder throwException(Class<? extends Throwable> exceptionType, String message)
+    {
+        check();
+
+        return throwException(cache.toTypeName(exceptionType), message);
+    }
+
+    public InstructionBuilder throwException()
+    {
+        check();
+
+        v.visitInsn(ATHROW);
+
+        return this;
+    }
+
+    public InstructionBuilder startSwitch(int min, int max, SwitchCallback callback)
+    {
+        check();
+
+        assert callback != null;
+
+        new SwitchBlockImpl(state, min, max).doCallback(callback);
+
+        return this;
+    }
+
+    public InstructionBuilder startVariable(String name, String type, InstructionBuilderCallback callback)
+    {
+        check();
+
+        Label start = state.newLabel();
+        Label end = new Label();
+
+        LocalVariable var = new LocalVariable(name, type, state.localIndex++);
+
+        v.visitLocalVariable(name, cache.toDesc(type), null, start, end, var.index);
+
+        LocalVariable prior = state.locals.put(name, var);
+
+        new InstructionBuilderImpl(state).doCallback(callback);
+
+        v.visitLabel(end);
+
+        state.localIndex--;
+
+        // Restore the original variable with this name, probably just null though.
+
+        state.locals.put(name, prior);
+
+        return this;
+    }
+
+    public InstructionBuilder storeVariable(String name)
+    {
+        check();
+
+        LocalVariable var = state.locals.get(name);
+
+        PrimitiveType type = PrimitiveType.getByName(var.type);
+
+        int opcode = type == null ? ASTORE : type.storeOpcode;
+
+        v.visitVarInsn(opcode, var.index);
+
+        return this;
+    }
+
+    public InstructionBuilder loadVariable(String name)
+    {
+        check();
+
+        LocalVariable var = state.locals.get(name);
+
+        PrimitiveType type = PrimitiveType.getByName(var.type);
+
+        int opcode = type == null ? ALOAD : type.loadOpcode;
+
+        v.visitVarInsn(opcode, var.index);
+
+        return this;
+    }
+
+    public InstructionBuilder ifZero(InstructionBuilderCallback ifTrue, InstructionBuilderCallback ifFalse)
+    {
+        doConditional(IFEQ, ifTrue, ifFalse);
+
+        return this;
+    }
+
+    public InstructionBuilder ifNull(InstructionBuilderCallback ifTrue, InstructionBuilderCallback ifFalse)
+    {
+        doConditional(IFNULL, ifTrue, ifFalse);
+
+        return this;
+    }
+
+    private void doConditional(int opcode, InstructionBuilderCallback ifTrueCallback,
+            InstructionBuilderCallback ifFalseCallback)
+    {
+        check();
+
+        Label ifTrueLabel = new Label();
+        Label endIfLabel = new Label();
+
+        // Kind of clumsy code, but it will work.
+
+        v.visitJumpInsn(opcode, ifTrueLabel);
+
+        new InstructionBuilderImpl(state).doCallback(ifFalseCallback);
+
+        v.visitJumpInsn(GOTO, endIfLabel);
+        v.visitLabel(ifTrueLabel);
+
+        new InstructionBuilderImpl(state).doCallback(ifTrueCallback);
+
+        v.visitLabel(endIfLabel);
+    }
+
+    void doCallback(InstructionBuilderCallback callback)
+    {
+        check();
+
+        if (callback != null)
+            callback.doBuild(this);
+
+        lock();
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderState.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderState.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderState.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InstructionBuilderState.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,58 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.util.Map;
+
+import org.apache.tapestry5.plastic.MethodDescription;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Stores information about the method whose instructions are being constructed, to make it easier
+ * to share data across multiple instances.
+ */
+public class InstructionBuilderState
+{
+    final MethodDescription description;
+
+    final MethodVisitor visitor;
+
+    final NameCache nameCache;
+
+    int localIndex;
+
+    final Map<String, LocalVariable> locals = PlasticInternalUtils.newMap();
+
+    protected InstructionBuilderState(MethodDescription description, MethodVisitor visitor, NameCache nameCache)
+    {
+        this.description = description;
+        this.visitor = visitor;
+        this.nameCache = nameCache;
+
+        // TODO: Account for static methods?
+
+        localIndex = 1 + description.argumentTypes.length;
+    }
+
+    Label newLabel()
+    {
+        Label result = new Label();
+
+        visitor.visitLabel(result);
+
+        return result;
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/LocalVariable.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/LocalVariable.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/LocalVariable.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/LocalVariable.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,32 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+public class LocalVariable
+{
+    final String name;
+
+    final String type;
+
+    // Adjusted index i.e., 1 + # of args + var index
+    final int index;
+
+    LocalVariable(String name, String type, int index)
+    {
+        this.name = name;
+        this.type = type;
+        this.index = index;
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/Lockable.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,38 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+/**
+ * An object that can be locked, at which point most of its functionality is disabled. This conforms to general
+ * builder approach used throughout Plastic where objects have an active construction phase, but are then locked
+ * (to encourage user code to discard them after they are no longer of any use).
+ */
+public class Lockable
+{
+    private boolean locked;
+
+    protected void check()
+    {
+        if (locked)
+            throw new IllegalStateException(toString() + " has been locked and can no longer be used.");
+    }
+
+    protected void lock()
+    {
+        check();
+
+        locked = true;
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,115 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Used to track which methods are implemented by a base class, which is often needed when transforming
+ * a subclass.
+ */
+public class MethodBundle
+{
+    private final MethodBundle parent;
+
+    private final Set<String> methods = new HashSet<String>();
+
+    // TODO: So far, this is just a placeholder until we figure out what the API should look like.
+    // TODO: Possibly, rename this class and have it store additional information, such as the name of a
+    // (protected final) field storing the InstanceContext.
+
+    public MethodBundle()
+    {
+        this(null);
+    }
+
+    private MethodBundle(MethodBundle parent)
+    {
+        this.parent = parent;
+    }
+
+    /**
+     * Is this bundle for a transformed class, or for a base class (typically Object)?
+     * 
+     * @return
+     *         true if this bundle is for transformed class, false otherwise
+     */
+    public boolean isTransformed()
+    {
+        return parent != null;
+    }
+
+    /**
+     * Returns a new MethodBundle that represents the methods of a child class
+     * of this bundle. The returned bundle will always be {@linkplain #isTransformed() transformed}.
+     * 
+     * @param childClassName
+     *            name of subclass
+     * @return new method bundle
+     */
+    public MethodBundle createChild(String childClassName)
+    {
+        return new MethodBundle(this);
+    }
+
+    /**
+     * Adds a new instance method. Only non-private, non-abstract methods should be added (that is, methods which might
+     * be overridden in subclasses). This can later be queried to see if any base class implements the method.
+     * 
+     * @param name
+     *            name of method
+     * @param desc
+     *            method descriptor
+     */
+    public void addMethod(String name, String desc)
+    {
+        String value = toValue(name, desc);
+
+        methods.add(value);
+    }
+
+    /**
+     * Returns true if a transformed parent class contains the indicated method.
+     * 
+     * @param name
+     *            method name
+     * @param desc
+     *            method descriptor
+     * @return the <em>internal name</em> of the implementing base class for this method,
+     *         or null if no base class implements the method
+     */
+    public boolean isImplemented(String name, String desc)
+    {
+        return checkForMethod(toValue(name, desc));
+    }
+
+    private boolean checkForMethod(String value)
+    {
+        if (methods.contains(value))
+            return true;
+
+        return parent == null ? false : parent.checkForMethod(value);
+    }
+
+    /**
+     * Combines a method name and its desc (which describes parameter types and return value) to form
+     * a value, which is how methods are tracked.
+     */
+    private String toValue(String name, String desc)
+    {
+        return name + ":" + desc;
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodHandleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodHandleImpl.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodHandleImpl.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodHandleImpl.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,51 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.MethodHandle;
+import org.apache.tapestry5.plastic.MethodInvocationResult;
+
+public class MethodHandleImpl implements MethodHandle
+{
+    private final String className, methodDescription;
+
+    private final int methodIndex;
+
+    protected volatile PlasticClassHandleShim shim;
+
+    public MethodHandleImpl(String className, String methodDescription, int methodIndex)
+    {
+        this.className = className;
+        this.methodDescription = methodDescription;
+        this.methodIndex = methodIndex;
+    }
+
+    public String toString()
+    {
+        return String.format("MethodHandle[%s %s]", className, methodDescription);
+    }
+
+    public MethodInvocationResult invoke(Object instance, Object... arguments)
+    {
+
+        if (instance == null)
+            throw new NullPointerException(String.format(
+                    "Unable to invoke method %s of class %s, as provided instance is null.", methodDescription,
+                    className));
+
+        return shim.invoke(instance, methodIndex, arguments);
+    }
+
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NameCache.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NameCache.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NameCache.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NameCache.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,125 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.MethodDescription;
+
+/**
+ * A cache of translations from type names to internal names and descriptors, as well as a cache from MethodDescription
+ * to method descriptor.
+ */
+@SuppressWarnings("rawtypes")
+public class NameCache
+{
+    private final Cache<String, String> class2internal = new Cache<String, String>()
+    {
+
+        @Override
+        protected String convert(String className)
+        {
+            return PlasticInternalUtils.toInternalName(className);
+        }
+    };
+
+    private final Cache<Class, String> type2internal = new Cache<Class, String>()
+    {
+        @Override
+        protected String convert(Class input)
+        {
+            return toInternalName(input.getName());
+        };
+    };
+
+    private final Cache<MethodDescription, String> md2desc = new Cache<MethodDescription, String>()
+    {
+        @Override
+        protected String convert(MethodDescription methodDescription)
+        {
+            return toMethodDescriptor(methodDescription.returnType, methodDescription.argumentTypes);
+        }
+    };
+
+    private final Cache<String, String> type2desc = new Cache<String, String>()
+    {
+        @Override
+        protected String convert(String typeName)
+        {
+            return PlasticInternalUtils.toDescriptor(typeName);
+        }
+    };
+
+    private final Cache<Class, String> typeToTypeName = new Cache<Class, String>()
+    {
+        @Override
+        protected String convert(Class type)
+        {
+            return PlasticInternalUtils.toTypeName(type);
+        };
+    };
+
+    public String toInternalName(String className)
+    {
+        return class2internal.get(className);
+    }
+
+    public String toInternalName(Class type)
+    {
+        return type2internal.get(type);
+    }
+
+    public String toDesc(MethodDescription md)
+    {
+        return md2desc.get(md);
+    }
+
+    public String toDesc(String typeName)
+    {
+        return type2desc.get(typeName);
+    }
+
+    public String toTypeName(Class type)
+    {
+        return typeToTypeName.get(type);
+    }
+
+    public String[] toTypeNames(Class... types)
+    {
+        String[] result = new String[types.length];
+
+        for (int i = 0; i < result.length; i++)
+            result[i] = toTypeName(types[i]);
+
+        return result;
+    }
+
+    public String toMethodDescriptor(Class returnType, Class... argumentTypes)
+    {
+        return toMethodDescriptor(toTypeName(returnType), toTypeNames(argumentTypes));
+    }
+
+    public String toMethodDescriptor(String returnType, String... argumentTypes)
+    {
+        StringBuilder builder = new StringBuilder("(");
+
+        for (String argumentType : argumentTypes)
+        {
+            builder.append(toDesc(argumentType));
+        }
+
+        builder.append(")").append(toDesc(returnType));
+
+        return builder.toString();
+    }
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NoopDelegate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NoopDelegate.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NoopDelegate.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/NoopDelegate.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,32 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.PlasticClass;
+import org.apache.tapestry5.plastic.PlasticManagerDelegate;
+
+public class NoopDelegate implements PlasticManagerDelegate
+{
+    public void transform(PlasticClass plasticClass)
+    {
+    }
+
+    public ClassInstantiator configureInstantiator(String className, ClassInstantiator instantiator)
+    {
+        return instantiator;
+    }
+
+}

Added: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassHandleShim.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassHandleShim.java?rev=1086644&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassHandleShim.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassHandleShim.java Tue Mar 29 17:24:31 2011
@@ -0,0 +1,74 @@
+// Copyright 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.plastic;
+
+import org.apache.tapestry5.plastic.FieldHandle;
+import org.apache.tapestry5.plastic.MethodHandle;
+import org.apache.tapestry5.plastic.MethodInvocationResult;
+import org.apache.tapestry5.plastic.PlasticClass;
+
+/**
+ * The interface for a "shim" class that provides the necessary hooks needed
+ * by {@link FieldHandle} and {@link MethodHandle} implementations for a particular,
+ * instantiated {@link PlasticClass}.
+ */
+public abstract class PlasticClassHandleShim
+{
+    /**
+     * Gets the field at the given index.
+     * 
+     * @param instance
+     *            object to read instance field from
+     * @param fieldIndex
+     *            assigned index for the field
+     * @return the field's value
+     * @see FieldHandle#get(Object)
+     */
+    public Object get(Object instance, int fieldIndex)
+    {
+        return null;
+    }
+
+    /**
+     * Sets the value of a field.
+     * 
+     * @param instance
+     *            object to update instance field in
+     * @param fieldIndex
+     *            assigned index for the field
+     * @param newValue
+     *            new value for field
+     * @see FieldHandle#set(Object, Object)
+     */
+    public void set(Object instance, int fieldIndex, Object newValue)
+    {
+    }
+
+    /**
+     * Invokes a method.
+     * 
+     * @param instance
+     *            object to invoke a method upon
+     * @param methodIndex
+     *            assigned index for the method
+     * @param arguments
+     *            arguments to pass to the method
+     * @return result of invoking the method
+     */
+    public MethodInvocationResult invoke(Object instance, int methodIndex, Object[] arguments)
+    {
+        return null;
+    }
+}