Author: hlship
Date: Thu Mar  4 19:14:27 2010
New Revision: 919137

URL: http://svn.apache.org/viewvc?rev=919137&view=rev
Log:
TAP5-1035: Use UnknownValueException when unable to bind a mixin field to a 
containing component parameter

Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java?rev=919137&r1=919136&r2=919137&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/BindParameterWorker.java
 Thu Mar  4 19:14:27 2010
@@ -20,9 +20,11 @@
 import org.apache.tapestry5.annotations.BindParameter;
 import org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.services.ComponentClassCache;
+import org.apache.tapestry5.ioc.internal.util.AvailableValues;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.apache.tapestry5.ioc.internal.util.UnknownValueException;
 import org.apache.tapestry5.ioc.services.FieldValueConduit;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.model.ComponentModel;
@@ -30,6 +32,7 @@
 import org.apache.tapestry5.services.ClassTransformation;
 import org.apache.tapestry5.services.ComponentClassTransformWorker;
 import org.apache.tapestry5.services.ComponentValueProvider;
+import org.apache.tapestry5.services.TransformField;
 
 /**
  * Responsible for identifying, via the {...@link 
org.apache.tapestry5.annotations.BindParameter} annotation, mixin fields
@@ -39,6 +42,61 @@
  */
 public class BindParameterWorker implements ComponentClassTransformWorker
 {
+    private final class BoundParameterFieldValueConduit implements 
FieldValueConduit
+    {
+        private final String containerParameterName;
+
+        private final InternalComponentResources containerResources;
+
+        private final Class fieldType;
+
+        private ParameterConduit conduit;
+
+        private BoundParameterFieldValueConduit(String containerParameterName,
+                InternalComponentResources containerResources, Class fieldType)
+        {
+            this.containerParameterName = containerParameterName;
+            this.containerResources = containerResources;
+            this.fieldType = fieldType;
+        }
+
+        /**
+         * Defer obtaining the conduit object until needed, to deal with the 
complex
+         * lifecycle of
+         * parameters. Perhaps this can be addressed by converting 
constructors into
+         * methods invoked
+         * from the page loaded lifecycle method?
+         */
+        private ParameterConduit getParameterConduit()
+        {
+            if (conduit == null)
+            {
+                conduit = 
containerResources.getParameterConduit(containerParameterName);
+
+            }
+
+            return conduit;
+        }
+
+        public void set(Object newValue)
+        {
+            getParameterConduit().set(newValue);
+        }
+
+        @SuppressWarnings("unchecked")
+        public Object get()
+        {
+            // For the moment, this results in two passes through the 
TypeCoercer; we'll look
+            // to optimize that in the future. The first pass is deep inside 
ParameterConduit (coercing
+            // to the component parameter field type), the second is here 
(usually the same type so no
+            // real coercion necessary).
+
+            Object result = getParameterConduit().get();
+
+            return typeCoercer.coerce(result, fieldType);
+        }
+    }
+
     private final TypeCoercer typeCoercer;
 
     private final ComponentClassCache componentClassCache;
@@ -51,93 +109,62 @@
 
     public void transform(final ClassTransformation transformation, 
MutableComponentModel model)
     {
-        List<String> fieldNames = 
transformation.findFieldsWithAnnotation(BindParameter.class);
+        for (TransformField field : 
transformation.matchFieldsWithAnnotation(BindParameter.class))
+            convertFieldIntoContainerBoundParameter(field);
+    }
 
-        for (String fieldName : fieldNames)
-        {
-            BindParameter annotation = 
transformation.getFieldAnnotation(fieldName,
-                    BindParameter.class);
+    private void convertFieldIntoContainerBoundParameter(TransformField field)
+    {
+        BindParameter annotation = field.getAnnotation(BindParameter.class);
 
-            convertFieldIntoContainerBoundParameter(fieldName, annotation, 
transformation);
-        }
+        field.claim(annotation);
 
-    }
+        final String[] possibleNames = annotation.value();
 
-    private void convertFieldIntoContainerBoundParameter(final String 
fieldName,
-            final BindParameter annotation, ClassTransformation transformation)
-    {
-        final String fieldTypeName = transformation.getFieldType(fieldName);
+        final String fieldTypeName = field.getType();
 
-        transformation.claimField(fieldName, annotation);
+        final String fieldName = field.getName();
 
         ComponentValueProvider<FieldValueConduit> provider = new 
ComponentValueProvider<FieldValueConduit>()
         {
-
             public FieldValueConduit get(final ComponentResources resources)
             {
-                if (!resources.isMixin())
-                    throw new 
TapestryException(TransformMessages.bindParameterOnlyOnMixin(
-                            fieldName, resources), null);
+                try
+                {
+                    return createFieldValueConduit(resources, fieldTypeName, 
fieldName, possibleNames);
+                }
+                catch (Exception ex)
+                {
+                    throw new TapestryException(String.format("Failure binding 
parameter field '%s' of mixin %s (type %s): %s",
+                            fieldName, resources.getCompleteId(),
+                            
resources.getComponentModel().getComponentClassName(), 
InternalUtils.toMessage(ex)), ex);
+                }
+            }
 
-                final InternalComponentResources containerResources = 
(InternalComponentResources) resources
-                        .getContainerResources();
+        };
 
-                // Evaluate this early so that we get a fast fail.
+        field.replaceAccess(provider);
+    }
 
-                final String containerParameterName = 
identifyParameterName(resources,
-                        InternalUtils.stripMemberName(fieldName), 
annotation.value());
+    private FieldValueConduit createFieldValueConduit(final ComponentResources 
resources, final String fieldTypeName,
+            final String fieldName, final String[] possibleNames)
+    {
+        if (!resources.isMixin())
+            throw new 
TapestryException(TransformMessages.bindParameterOnlyOnMixin(fieldName, 
resources), null);
 
-                final Class fieldType = 
componentClassCache.forName(fieldTypeName);
+        InternalComponentResources containerResources = 
(InternalComponentResources) resources.getContainerResources();
 
-                return new FieldValueConduit()
-                {
-                    private ParameterConduit conduit;
+        // Evaluate this early so that we get a fast fail.
 
-                    /**
-                     * Defer obtaining the conduit object until needed, to 
deal with the complex
-                     * lifecycle of
-                     * parameters. Perhaps this can be addressed by converting 
constructors into
-                     * methods invoked
-                     * from the page loaded lifecycle method?
-                     */
-                    private ParameterConduit getParameterConduit()
-                    {
-                        if (conduit == null)
-                        {
-                            conduit = containerResources
-                                    
.getParameterConduit(containerParameterName);
-
-                        }
-
-                        return conduit;
-                    }
-
-                    public void set(Object newValue)
-                    {
-                        getParameterConduit().set(newValue);
-                    }
-
-                    @SuppressWarnings("unchecked")
-                    public Object get()
-                    {
-                        // For the moment, this results in two passes through 
the TypeCoercer; we'll look
-                        // to optimize that in the future. The first pass is 
deep inside ParameterConduit (coercing
-                        // to the component parameter field type), the second 
is here (usually the same type so no
-                        // real coercion necessary).
-
-                        Object result = getParameterConduit().get();
-
-                        return typeCoercer.coerce(result, fieldType);
-                    }
-                };
-            }
-        };
+        String containerParameterName = identifyParameterName(resources, 
InternalUtils.stripMemberName(fieldName),
+                possibleNames);
+
+        Class fieldType = componentClassCache.forName(fieldTypeName);
 
-        transformation.getField(fieldName).replaceAccess(provider);
+        return new BoundParameterFieldValueConduit(containerParameterName, 
containerResources, fieldType);
     }
 
-    private String identifyParameterName(ComponentResources resources, String 
firstGuess,
-            String... otherGuesses)
+    private String identifyParameterName(ComponentResources resources, String 
firstGuess, String... otherGuesses)
     {
         ComponentModel model = 
resources.getContainerResources().getComponentModel();
 
@@ -155,21 +182,15 @@
                 return name;
         }
 
-        String message = String
-                .format(
-                        "Failed to bind parameter of mixin %s (type %s). 
Containing component %s does not contain a formal parameter %s %s. Formal 
parameters: %s.",
-                        resources.getCompleteId(),
-
-                        resources.getComponentModel().getComponentClassName(),
-
-                        model.getComponentClassName(),
+        String message = String.format("Containing component %s does not 
contain a formal parameter %s %s.",
 
-                        guesses.size() == 1 ? "matching" : "matching any of",
+        model.getComponentClassName(),
 
-                        InternalUtils.joinSorted(guesses),
+        guesses.size() == 1 ? "matching" : "matching any of",
 
-                        
InternalUtils.joinSorted(model.getDeclaredParameterNames()));
+        InternalUtils.joinSorted(guesses));
 
-        throw new TapestryException(message, resources.getLocation(), null);
+        throw new UnknownValueException(message, new AvailableValues("formal 
parameters", model
+                .getDeclaredParameterNames()));
     }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java?rev=919137&r1=919136&r2=919137&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
 Thu Mar  4 19:14:27 2010
@@ -1282,7 +1282,9 @@
         assertTextPresent(
                 "An unexpected application exception has occurred.",
 
-                "Failed to bind parameter of mixin 
BindParameterNoSuchParameter:throwexception$echovalue2 (type 
org.apache.tapestry5.integration.app1.mixins.EchoValue2). Containing component 
org.apache.tapestry5.corelib.components.Any does not contain a formal parameter 
matching any of boundParameter, value. Formal parameters: clientId, element.");
+                "Failure binding parameter field 'boundParameter' of mixin 
BindParameterNoSuchParameter:throwexception$echovalue2 (type 
org.apache.tapestry5.integration.app1.mixins.EchoValue2)",
+
+                "Containing component 
org.apache.tapestry5.corelib.components.Any does not contain a formal parameter 
matching any of boundParameter, value.");
     }
 
     @Test


Reply via email to