You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/07/08 19:35:59 UTC

svn commit: r1144398 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/pageload/ main/resources/org/apache/tapestry5/internal/pageload/ test/groovy/org/apache/tapestry5/integration/app1/ test/java/org/apache/tape...

Author: hlship
Date: Fri Jul  8 17:35:58 2011
New Revision: 1144398

URL: http://svn.apache.org/viewvc?rev=1144398&view=rev
Log:
TAP5-1428: When a parameter is bound but does not match a formal parameter, the exception should also include a list of formal parameter names

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java Fri Jul  8 17:35:58 2011
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 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.
@@ -17,6 +17,8 @@ package org.apache.tapestry5.internal.pa
 import org.apache.tapestry5.internal.structure.ComponentPageElement;
 import org.apache.tapestry5.ioc.Locatable;
 
+import java.util.Set;
+
 /**
  * Encapsulates logic related to assembling an embedded component within a {@link org.apache.tapestry5.internal.pageload.ComponentAssembler}.
  */
@@ -39,7 +41,8 @@ interface EmbeddedComponentAssembler ext
      * This method should only be called at page-assembly time as it requires some data that is collected during
      * ComponentAssembly construction in order to handle published parameters of embedded components.
      *
-     * @param parameterName simple or qualified parameter name
+     * @param parameterName
+     *         simple or qualified parameter name
      * @return object that can bind the parameter
      */
     ParameterBinder createParameterBinder(String parameterName);
@@ -59,7 +62,15 @@ interface EmbeddedComponentAssembler ext
     /**
      * Adds mixins to the newly created embedded element.
      *
-     * @param newElement new element requiring mixins
+     * @param newElement
+     *         new element requiring mixins
      */
     void addMixinsToElement(ComponentPageElement newElement);
+
+    /**
+     * Returns the names of all formal parameters.
+     *
+     * @since 5.3
+     */
+    Set<String> getFormalParameterNames();
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java Fri Jul  8 17:35:58 2011
@@ -14,8 +14,6 @@
 
 package org.apache.tapestry5.internal.pageload;
 
-import java.util.Map;
-
 import org.apache.tapestry5.internal.TapestryInternalUtils;
 import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
 import org.apache.tapestry5.internal.services.Instantiator;
@@ -30,6 +28,10 @@ import org.apache.tapestry5.model.Embedd
 import org.apache.tapestry5.services.ComponentClassResolver;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
 public class EmbeddedComponentAssemblerImpl implements EmbeddedComponentAssembler
 {
     private final ComponentInstantiatorSource instantiatorSource;
@@ -60,24 +62,24 @@ public class EmbeddedComponentAssemblerI
     /**
      * @param assemblerSource
      * @param instantiatorSource
-     *            used to access component models
+     *         used to access component models
      * @param componentClassResolver
-     *            used to convert mixin types to component models
+     *         used to convert mixin types to component models
      * @param componentClassName
-     *            class name of embedded component
+     *         class name of embedded component
      * @param selector
-     *            used to select template and other resources
+     *         used to select template and other resources
      * @param embeddedModel
-     *            embedded model (may be null for components defined in the template)
+     *         embedded model (may be null for components defined in the template)
      * @param templateMixins
-     *            list of mixins from the t:mixins element (possibly null)
+     *         list of mixins from the t:mixins element (possibly null)
      * @param location
-     *            location of components element in its container's template
+     *         location of components element in its container's template
      */
     public EmbeddedComponentAssemblerImpl(ComponentAssemblerSource assemblerSource,
-            ComponentInstantiatorSource instantiatorSource, ComponentClassResolver componentClassResolver,
-            String componentClassName, ComponentResourceSelector selector, EmbeddedComponentModel embeddedModel,
-            String templateMixins, Location location)
+                                          ComponentInstantiatorSource instantiatorSource, ComponentClassResolver componentClassResolver,
+                                          String componentClassName, ComponentResourceSelector selector, EmbeddedComponentModel embeddedModel,
+                                          String templateMixins, Location location)
     {
         this.assemblerSource = assemblerSource;
         this.instantiatorSource = instantiatorSource;
@@ -186,11 +188,13 @@ public class EmbeddedComponentAssemblerI
         if (dotx >= 0)
         {
             String mixinId = parameterName.substring(0, dotx);
-            if (!mixinIdToInstantiator.containsKey(mixinId)) { throw new TapestryException(
-                    PageloadMessages.mixinidForParamnotfound(parameterName, mixinIdToInstantiator.keySet()), location,
-                    null); }
-        }
-        else
+            if (!mixinIdToInstantiator.containsKey(mixinId))
+            {
+                throw new TapestryException(
+                        PageloadMessages.mixinidForParamnotfound(parameterName, mixinIdToInstantiator.keySet()), location,
+                        null);
+            }
+        } else
         {
             // Unqualified parameter name. May be a reference not to a parameter of this component, but a published
             // parameter of a component embedded in this component. The ComponentAssembler for this component
@@ -251,4 +255,9 @@ public class EmbeddedComponentAssemblerI
     {
         return location;
     }
+
+    public Set<String> getFormalParameterNames()
+    {
+        return new HashSet<String>(componentModel.getParameterNames());
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java Fri Jul  8 17:35:58 2011
@@ -14,11 +14,6 @@
 
 package org.apache.tapestry5.internal.pageload;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.BindingConstants;
 import org.apache.tapestry5.ComponentResources;
@@ -26,38 +21,9 @@ import org.apache.tapestry5.MarkupWriter
 import org.apache.tapestry5.internal.InternalComponentResources;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.bindings.LiteralBinding;
-import org.apache.tapestry5.internal.parser.AttributeToken;
-import org.apache.tapestry5.internal.parser.BlockToken;
-import org.apache.tapestry5.internal.parser.CDATAToken;
-import org.apache.tapestry5.internal.parser.CommentToken;
-import org.apache.tapestry5.internal.parser.ComponentTemplate;
-import org.apache.tapestry5.internal.parser.DTDToken;
-import org.apache.tapestry5.internal.parser.DefineNamespacePrefixToken;
-import org.apache.tapestry5.internal.parser.ExpansionToken;
-import org.apache.tapestry5.internal.parser.ExtensionPointToken;
-import org.apache.tapestry5.internal.parser.ParameterToken;
-import org.apache.tapestry5.internal.parser.StartComponentToken;
-import org.apache.tapestry5.internal.parser.StartElementToken;
-import org.apache.tapestry5.internal.parser.TemplateToken;
-import org.apache.tapestry5.internal.parser.TextToken;
-import org.apache.tapestry5.internal.parser.TokenType;
-import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
-import org.apache.tapestry5.internal.services.ComponentTemplateSource;
-import org.apache.tapestry5.internal.services.Instantiator;
-import org.apache.tapestry5.internal.services.PageElementFactory;
-import org.apache.tapestry5.internal.services.PageLoader;
-import org.apache.tapestry5.internal.services.PersistentFieldManager;
-import org.apache.tapestry5.internal.services.StringInterner;
-import org.apache.tapestry5.internal.structure.BlockImpl;
-import org.apache.tapestry5.internal.structure.CommentPageElement;
-import org.apache.tapestry5.internal.structure.ComponentPageElement;
-import org.apache.tapestry5.internal.structure.ComponentPageElementResources;
-import org.apache.tapestry5.internal.structure.ComponentPageElementResourcesSource;
-import org.apache.tapestry5.internal.structure.DTDPageElement;
-import org.apache.tapestry5.internal.structure.Page;
-import org.apache.tapestry5.internal.structure.PageImpl;
-import org.apache.tapestry5.internal.structure.StartElementPageElement;
-import org.apache.tapestry5.internal.structure.TextPageElement;
+import org.apache.tapestry5.internal.parser.*;
+import org.apache.tapestry5.internal.services.*;
+import org.apache.tapestry5.internal.structure.*;
 import org.apache.tapestry5.ioc.Invokable;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.OperationTracker;
@@ -66,7 +32,9 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.ioc.services.SymbolSource;
+import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.Stack;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
 import org.apache.tapestry5.model.ComponentModel;
 import org.apache.tapestry5.model.EmbeddedComponentModel;
 import org.apache.tapestry5.runtime.RenderCommand;
@@ -76,6 +44,10 @@ import org.apache.tapestry5.services.Inv
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
 /**
  * There's still a lot of room to beef up {@link org.apache.tapestry5.internal.pageload.ComponentAssembler} and
  * {@link org.apache.tapestry5.internal.pageload.EmbeddedComponentAssembler} to perform more static analysis, but
@@ -92,23 +64,19 @@ import org.apache.tapestry5.services.pag
  * <p/>
  * And truly, <em>This is the Tapestry Heart, This is the Tapestry Soul...</em>
  */
-public class PageLoaderImpl implements PageLoader, InvalidationListener, ComponentAssemblerSource
-{
-    private static final class Key
-    {
+public class PageLoaderImpl implements PageLoader, InvalidationListener, ComponentAssemblerSource {
+    private static final class Key {
         private final String className;
 
         private final ComponentResourceSelector selector;
 
-        private Key(String className, ComponentResourceSelector selector)
-        {
+        private Key(String className, ComponentResourceSelector selector) {
             this.className = className;
             this.selector = selector;
         }
 
         @Override
-        public boolean equals(Object o)
-        {
+        public boolean equals(Object o) {
             if (this == o)
                 return true;
             if (o == null || getClass() != o.getClass())
@@ -120,32 +88,26 @@ public class PageLoaderImpl implements P
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return 31 * className.hashCode() + selector.hashCode();
         }
     }
 
-    private static final PageAssemblyAction POP_EMBEDDED_COMPONENT_ACTION = new PageAssemblyAction()
-    {
-        public void execute(PageAssembly pageAssembly)
-        {
+    private static final PageAssemblyAction POP_EMBEDDED_COMPONENT_ACTION = new PageAssemblyAction() {
+        public void execute(PageAssembly pageAssembly) {
             pageAssembly.createdElement.pop();
             pageAssembly.bodyElement.pop();
             pageAssembly.embeddedAssembler.pop();
         }
     };
 
-    private static final RenderCommand END_ELEMENT = new RenderCommand()
-    {
-        public void render(MarkupWriter writer, RenderQueue queue)
-        {
+    private static final RenderCommand END_ELEMENT = new RenderCommand() {
+        public void render(MarkupWriter writer, RenderQueue queue) {
             writer.end();
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return "End";
         }
     };
@@ -175,11 +137,10 @@ public class PageLoaderImpl implements P
     private final SymbolSource symbolSource;
 
     public PageLoaderImpl(ComponentInstantiatorSource instantiatorSource, ComponentTemplateSource templateSource,
-            PageElementFactory elementFactory, ComponentPageElementResourcesSource resourcesSource,
-            ComponentClassResolver componentClassResolver, PersistentFieldManager persistentFieldManager,
-            StringInterner interner, OperationTracker tracker, PerthreadManager perThreadManager, Request request,
-            SymbolSource symbolSource)
-    {
+                          PageElementFactory elementFactory, ComponentPageElementResourcesSource resourcesSource,
+                          ComponentClassResolver componentClassResolver, PersistentFieldManager persistentFieldManager,
+                          StringInterner interner, OperationTracker tracker, PerthreadManager perThreadManager, Request request,
+                          SymbolSource symbolSource) {
         this.instantiatorSource = instantiatorSource;
         this.templateSource = templateSource;
         this.elementFactory = elementFactory;
@@ -193,19 +154,15 @@ public class PageLoaderImpl implements P
         this.symbolSource = symbolSource;
     }
 
-    public void objectWasInvalidated()
-    {
+    public void objectWasInvalidated() {
         cache.clear();
     }
 
-    public Page loadPage(final String logicalPageName, final ComponentResourceSelector selector)
-    {
+    public Page loadPage(final String logicalPageName, final ComponentResourceSelector selector) {
         final String pageClassName = componentClassResolver.resolvePageNameToClassName(logicalPageName);
 
-        return tracker.invoke("Constructing instance of page class " + pageClassName, new Invokable<Page>()
-        {
-            public Page invoke()
-            {
+        return tracker.invoke("Constructing instance of page class " + pageClassName, new Invokable<Page>() {
+            public Page invoke() {
                 Page page = new PageImpl(logicalPageName, selector, persistentFieldManager, perThreadManager);
 
                 ComponentAssembler assembler = getAssembler(pageClassName, selector);
@@ -225,14 +182,12 @@ public class PageLoaderImpl implements P
         });
     }
 
-    public ComponentAssembler getAssembler(String className, ComponentResourceSelector selector)
-    {
+    public ComponentAssembler getAssembler(String className, ComponentResourceSelector selector) {
         Key key = new Key(className, selector);
 
         ComponentAssembler result = cache.get(key);
 
-        if (result == null)
-        {
+        if (result == null) {
             // There's a window here where two threads may create the same assembler simultaneously;
             // the extra assembler will be discarded.
 
@@ -244,12 +199,9 @@ public class PageLoaderImpl implements P
         return result;
     }
 
-    private ComponentAssembler createAssembler(final String className, final ComponentResourceSelector selector)
-    {
-        return tracker.invoke("Creating ComponentAssembler for " + className, new Invokable<ComponentAssembler>()
-        {
-            public ComponentAssembler invoke()
-            {
+    private ComponentAssembler createAssembler(final String className, final ComponentResourceSelector selector) {
+        return tracker.invoke("Creating ComponentAssembler for " + className, new Invokable<ComponentAssembler>() {
+            public ComponentAssembler invoke() {
                 Instantiator instantiator = instantiatorSource.getInstantiator(className);
 
                 ComponentModel componentModel = instantiator.getModel();
@@ -275,14 +227,12 @@ public class PageLoaderImpl implements P
      * "Programs" the assembler by analyzing the component, its mixins and its embedded components (both in the template
      * and in the Java class), adding new PageAssemblyActions.
      */
-    private void programAssembler(ComponentAssembler assembler, ComponentTemplate template)
-    {
+    private void programAssembler(ComponentAssembler assembler, ComponentTemplate template) {
         TokenStream stream = createTokenStream(assembler, template);
 
         AssemblerContext context = new AssemblerContext(assembler, stream);
 
-        if (template.isMissing())
-        {
+        if (template.isMissing()) {
             // Pretend the template has a single <t:body> element.
 
             body(context);
@@ -290,8 +240,7 @@ public class PageLoaderImpl implements P
             return;
         }
 
-        while (context.more())
-        {
+        while (context.more()) {
             processTemplateToken(context);
         }
 
@@ -303,8 +252,7 @@ public class PageLoaderImpl implements P
      * {@link org.apache.tapestry5.internal.parser.ExtensionPointToken}s
      * and replacing them with appropriate overrides. Also validates that all embedded ids are accounted for.
      */
-    private TokenStream createTokenStream(ComponentAssembler assembler, ComponentTemplate template)
-    {
+    private TokenStream createTokenStream(ComponentAssembler assembler, ComponentTemplate template) {
         List<TemplateToken> tokens = CollectionFactory.newList();
 
         Stack<TemplateToken> queue = CollectionFactory.newStack();
@@ -318,21 +266,17 @@ public class PageLoaderImpl implements P
 
         pushAll(queue, baseTemplate.getTokens());
 
-        while (!queue.isEmpty())
-        {
+        while (!queue.isEmpty()) {
             TemplateToken token = queue.pop();
 
             // When an ExtensionPoint is found, it is replaced with the tokens of its override.
 
-            if (token.getTokenType().equals(TokenType.EXTENSION_POINT))
-            {
+            if (token.getTokenType().equals(TokenType.EXTENSION_POINT)) {
                 ExtensionPointToken extensionPointToken = (ExtensionPointToken) token;
 
                 queueOverrideTokensForExtensionPoint(extensionPointToken, queue, overrideSearch);
 
-            }
-            else
-            {
+            } else {
                 tokens.add(token);
             }
         }
@@ -343,8 +287,7 @@ public class PageLoaderImpl implements P
 
         Map<String, Location> componentIds = CollectionFactory.newCaseInsensitiveMap();
 
-        for (ComponentTemplate ct : overrideSearch)
-        {
+        for (ComponentTemplate ct : overrideSearch) {
             componentIds.putAll(ct.getComponentIds());
         }
 
@@ -356,26 +299,22 @@ public class PageLoaderImpl implements P
         return new TokenStreamImpl(tokens);
     }
 
-    private static <T> T getLast(List<T> list)
-    {
+    private static <T> T getLast(List<T> list) {
         int count = list.size();
 
         return list.get(count - 1);
     }
 
     private void queueOverrideTokensForExtensionPoint(ExtensionPointToken extensionPointToken,
-            Stack<TemplateToken> queue, List<ComponentTemplate> overrideSearch)
-    {
+                                                      Stack<TemplateToken> queue, List<ComponentTemplate> overrideSearch) {
         String extensionPointId = extensionPointToken.getExtensionPointId();
 
         // Work up from the component, through its base classes, towards the last non-extension template.
 
-        for (ComponentTemplate t : overrideSearch)
-        {
+        for (ComponentTemplate t : overrideSearch) {
             List<TemplateToken> tokens = t.getExtensionPointTokens(extensionPointId);
 
-            if (tokens != null)
-            {
+            if (tokens != null) {
                 pushAll(queue, tokens);
                 return;
             }
@@ -388,8 +327,7 @@ public class PageLoaderImpl implements P
                 extensionPointToken.getLocation(), null);
     }
 
-    private List<ComponentTemplate> buildOverrideSearch(ComponentAssembler assembler, ComponentTemplate template)
-    {
+    private List<ComponentTemplate> buildOverrideSearch(ComponentAssembler assembler, ComponentTemplate template) {
         List<ComponentTemplate> result = CollectionFactory.newList();
         result.add(template);
 
@@ -397,11 +335,12 @@ public class PageLoaderImpl implements P
 
         ComponentTemplate lastTemplate = template;
 
-        while (lastTemplate.isExtension())
-        {
+        while (lastTemplate.isExtension()) {
             ComponentModel parentModel = model.getParentModel();
 
-            if (parentModel == null) { throw new RuntimeException(PageloadMessages.noParentForExtension(model)); }
+            if (parentModel == null) {
+                throw new RuntimeException(PageloadMessages.noParentForExtension(model));
+            }
 
             ComponentTemplate parentTemplate = templateSource.getTemplate(parentModel, assembler.getSelector());
 
@@ -419,19 +358,16 @@ public class PageLoaderImpl implements P
      * Push all the tokens onto the stack, in reverse order, so that the last token is deepest and the first token is
      * most shallow (first to come off the queue).
      */
-    private void pushAll(Stack<TemplateToken> queue, List<TemplateToken> tokens)
-    {
+    private void pushAll(Stack<TemplateToken> queue, List<TemplateToken> tokens) {
         for (int i = tokens.size() - 1; i >= 0; i--)
             queue.push(tokens.get(i));
     }
 
-    private void processTemplateToken(AssemblerContext context)
-    {
+    private void processTemplateToken(AssemblerContext context) {
         // These tokens can appear at the top level, or at lower levels (this method is invoked
         // from token-processing loops inside element(), component(), etc.
 
-        switch (context.peekType())
-        {
+        switch (context.peekType()) {
             case TEXT:
 
                 text(context);
@@ -492,20 +428,16 @@ public class PageLoaderImpl implements P
         }
     }
 
-    private void cdata(AssemblerContext context)
-    {
+    private void cdata(AssemblerContext context) {
         final CDATAToken token = context.next(CDATAToken.class);
 
-        RenderCommand command = new RenderCommand()
-        {
-            public void render(MarkupWriter writer, RenderQueue queue)
-            {
+        RenderCommand command = new RenderCommand() {
+            public void render(MarkupWriter writer, RenderQueue queue) {
                 writer.cdata(token.getContent());
             }
 
             @Override
-            public String toString()
-            {
+            public String toString() {
                 return String.format("CDATA[%s]", token.getLocation());
             }
         };
@@ -514,20 +446,16 @@ public class PageLoaderImpl implements P
 
     }
 
-    private void defineNamespacePrefix(AssemblerContext context)
-    {
+    private void defineNamespacePrefix(AssemblerContext context) {
         final DefineNamespacePrefixToken token = context.next(DefineNamespacePrefixToken.class);
 
-        RenderCommand command = new RenderCommand()
-        {
-            public void render(MarkupWriter writer, RenderQueue queue)
-            {
+        RenderCommand command = new RenderCommand() {
+            public void render(MarkupWriter writer, RenderQueue queue) {
                 writer.defineNamespace(token.getNamespaceURI(), token.getNamespacePrefix());
             }
 
             @Override
-            public String toString()
-            {
+            public String toString() {
                 return String.format("DefineNamespace[%s %s]", token.getNamespacePrefix(), token.getNamespaceURI());
             }
         };
@@ -535,16 +463,12 @@ public class PageLoaderImpl implements P
         context.addComposable(command);
     }
 
-    private void dtd(AssemblerContext context)
-    {
+    private void dtd(AssemblerContext context) {
         final DTDToken token = context.next(DTDToken.class);
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
-                if (!pageAssembly.checkAndSetFlag("dtd-page-element-added"))
-                {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
+                if (!pageAssembly.checkAndSetFlag("dtd-page-element-added")) {
                     RenderCommand command = new DTDPageElement(token.getName(), token.getPublicId(), token
                             .getSystemId());
 
@@ -557,29 +481,33 @@ public class PageLoaderImpl implements P
         });
     }
 
-    private void parameter(AssemblerContext context)
-    {
+    private void parameter(AssemblerContext context) {
         final ParameterToken token = context.next(ParameterToken.class);
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 String parameterName = token.getName();
 
                 ComponentPageElement element = pageAssembly.createdElement.peek();
 
-                BlockImpl block = new BlockImpl(token.getLocation(), interner.format("Parameter %s of %s",
+                Location location = token.getLocation();
+
+                BlockImpl block = new BlockImpl(location, interner.format("Parameter %s of %s",
                         parameterName, element.getCompleteId()));
 
-                Binding binding = new LiteralBinding(token.getLocation(), "block parameter " + parameterName, block);
+                Binding binding = new LiteralBinding(location, "block parameter " + parameterName, block);
 
                 EmbeddedComponentAssembler embeddedAssembler = pageAssembly.embeddedAssembler.peek();
 
                 ParameterBinder binder = embeddedAssembler.createParameterBinder(parameterName);
 
-                if (binder == null) { throw new TapestryException(PageloadMessages.parameterNotSupported(
-                        element.getCompleteId(), parameterName), token.getLocation(), null); }
+                if (binder == null) {
+                    throw new UnknownValueException(
+                            String.format("Component %s does not include a formal parameter '%s' (and does not support informal parameters).",
+                                    element.getCompleteId(), parameterName), location,
+                            null,
+                            new AvailableValues("Formal parameters", embeddedAssembler.getFormalParameterNames()));
+                }
 
                 binder.bind(pageAssembly.createdElement.peek(), binding);
 
@@ -590,14 +518,11 @@ public class PageLoaderImpl implements P
         consumeToEndElementAndPopBodyElement(context);
     }
 
-    private void block(AssemblerContext context)
-    {
+    private void block(AssemblerContext context) {
         final BlockToken token = context.next(BlockToken.class);
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 String blockId = token.getId();
 
                 ComponentPageElement element = pageAssembly.activeElement.peek();
@@ -618,20 +543,15 @@ public class PageLoaderImpl implements P
         consumeToEndElementAndPopBodyElement(context);
     }
 
-    private void consumeToEndElementAndPopBodyElement(AssemblerContext context)
-    {
-        while (true)
-        {
-            switch (context.peekType())
-            {
+    private void consumeToEndElementAndPopBodyElement(AssemblerContext context) {
+        while (true) {
+            switch (context.peekType()) {
                 case END_ELEMENT:
 
                     context.next();
 
-                    context.add(new PageAssemblyAction()
-                    {
-                        public void execute(PageAssembly pageAssembly)
-                        {
+                    context.add(new PageAssemblyAction() {
+                        public void execute(PageAssembly pageAssembly) {
                             pageAssembly.bodyElement.pop();
                         }
                     });
@@ -644,8 +564,7 @@ public class PageLoaderImpl implements P
         }
     }
 
-    private void comment(AssemblerContext context)
-    {
+    private void comment(AssemblerContext context) {
         CommentToken token = context.next(CommentToken.class);
 
         RenderCommand commentElement = new CommentPageElement(token.getComment());
@@ -653,14 +572,11 @@ public class PageLoaderImpl implements P
         context.addComposable(commentElement);
     }
 
-    private void component(AssemblerContext context)
-    {
+    private void component(AssemblerContext context) {
         EmbeddedComponentAssembler embeddedAssembler = startComponent(context);
 
-        while (true)
-        {
-            switch (context.peekType())
-            {
+        while (true) {
+            switch (context.peekType()) {
                 case ATTRIBUTE:
 
                     bindAttributeAsParameter(context, embeddedAssembler);
@@ -681,26 +597,22 @@ public class PageLoaderImpl implements P
         }
     }
 
-    private void bindAttributeAsParameter(AssemblerContext context, EmbeddedComponentAssembler embeddedAssembler)
-    {
+    private void bindAttributeAsParameter(AssemblerContext context, EmbeddedComponentAssembler embeddedAssembler) {
         AttributeToken token = context.next(AttributeToken.class);
 
         addParameterBindingAction(context, embeddedAssembler, token.getName(), token.getValue(),
-                BindingConstants.LITERAL, token.getLocation());
+                BindingConstants.LITERAL, token.getLocation(), true);
     }
 
-    private void element(AssemblerContext context)
-    {
+    private void element(AssemblerContext context) {
         StartElementToken token = context.next(StartElementToken.class);
 
         RenderCommand element = new StartElementPageElement(token.getNamespaceURI(), token.getName());
 
         context.addComposable(element);
 
-        while (true)
-        {
-            switch (context.peekType())
-            {
+        while (true) {
+            switch (context.peekType()) {
                 case ATTRIBUTE:
                     attribute(context);
                     break;
@@ -721,8 +633,7 @@ public class PageLoaderImpl implements P
 
     }
 
-    private EmbeddedComponentAssembler startComponent(AssemblerContext context)
-    {
+    private EmbeddedComponentAssembler startComponent(AssemblerContext context) {
         StartComponentToken token = context.next(StartComponentToken.class);
 
         ComponentAssembler assembler = context.assembler;
@@ -742,12 +653,13 @@ public class PageLoaderImpl implements P
         if (embeddedId == null)
             embeddedId = assembler.generateEmbeddedId(embeddedType);
 
-        if (embeddedModel != null)
-        {
+        if (embeddedModel != null) {
             String modelType = embeddedModel.getComponentType();
 
-            if (InternalUtils.isNonBlank(modelType) && embeddedType != null) { throw new TapestryException(
-                    PageloadMessages.redundantEmbeddedComponentTypes(embeddedId, embeddedType, modelType), token, null); }
+            if (InternalUtils.isNonBlank(modelType) && embeddedType != null) {
+                throw new TapestryException(
+                        PageloadMessages.redundantEmbeddedComponentTypes(embeddedId, embeddedType, modelType), token, null);
+            }
 
             embeddedType = modelType;
             embeddedComponentClassName = embeddedModel.getComponentClassName();
@@ -758,19 +670,15 @@ public class PageLoaderImpl implements P
         // This awkwardness is making me think that the page loader should resolve the component
         // type before invoking this method (we would then remove the componentType parameter).
 
-        if (InternalUtils.isNonBlank(embeddedType))
-        {
+        if (InternalUtils.isNonBlank(embeddedType)) {
             // The type actually overrides the specified class name. The class name is defined
             // by the type of the field. In many scenarios, the field type is a common
             // interface,
             // and the type is used to determine the concrete class to instantiate.
 
-            try
-            {
+            try {
                 componentClassName = componentClassResolver.resolveComponentTypeToClassName(embeddedType);
-            }
-            catch (RuntimeException ex)
-            {
+            } catch (RuntimeException ex) {
                 throw new TapestryException(ex.getMessage(), token, ex);
             }
         }
@@ -784,22 +692,17 @@ public class PageLoaderImpl implements P
 
         addParameterBindingActions(context, embeddedAssembler, embeddedModel);
 
-        if (embeddedModel != null && embeddedModel.getInheritInformalParameters())
-        {
+        if (embeddedModel != null && embeddedModel.getInheritInformalParameters()) {
             // Another two-step: The first "captures" the container and embedded component. The second
             // occurs at the end of the page setup.
 
-            assembler.add(new PageAssemblyAction()
-            {
-                public void execute(PageAssembly pageAssembly)
-                {
+            assembler.add(new PageAssemblyAction() {
+                public void execute(PageAssembly pageAssembly) {
                     final ComponentPageElement container = pageAssembly.activeElement.peek();
                     final ComponentPageElement embedded = pageAssembly.createdElement.peek();
 
-                    pageAssembly.deferred.add(new PageAssemblyAction()
-                    {
-                        public void execute(PageAssembly pageAssembly)
-                        {
+                    pageAssembly.deferred.add(new PageAssemblyAction() {
+                        public void execute(PageAssembly pageAssembly) {
                             copyInformalParameters(container, embedded);
                         }
                     });
@@ -812,8 +715,7 @@ public class PageLoaderImpl implements P
 
     }
 
-    private void copyInformalParameters(ComponentPageElement container, ComponentPageElement embedded)
-    {
+    private void copyInformalParameters(ComponentPageElement container, ComponentPageElement embedded) {
         // TODO: Much more, this is an area where we can make things a bit more efficient by tracking
         // what has and hasn't been bound in the EmbeddedComponentAssembler (and identifying what is
         // and isn't informal).
@@ -822,8 +724,7 @@ public class PageLoaderImpl implements P
 
         Map<String, Binding> informals = container.getInformalParameterBindings();
 
-        for (String name : informals.keySet())
-        {
+        for (String name : informals.keySet()) {
             if (model.getParameterModel(name) != null)
                 continue;
 
@@ -834,41 +735,35 @@ public class PageLoaderImpl implements P
     }
 
     private void addParameterBindingActions(AssemblerContext context, EmbeddedComponentAssembler embeddedAssembler,
-            EmbeddedComponentModel embeddedModel)
-    {
+                                            EmbeddedComponentModel embeddedModel) {
         if (embeddedModel == null)
             return;
 
-        for (String parameterName : embeddedModel.getParameterNames())
-        {
+        for (String parameterName : embeddedModel.getParameterNames()) {
             String parameterValue = embeddedModel.getParameterValue(parameterName);
 
             addParameterBindingAction(context, embeddedAssembler, parameterName, parameterValue, BindingConstants.PROP,
-                    embeddedModel.getLocation());
+                    embeddedModel.getLocation(), false);
         }
     }
 
     private void addParameterBindingAction(AssemblerContext context,
-            final EmbeddedComponentAssembler embeddedAssembler, final String parameterName,
-            final String parameterValue, final String metaDefaultBindingPrefix, final Location location)
-    {
+                                           final EmbeddedComponentAssembler embeddedAssembler, final String parameterName,
+                                           final String parameterValue, final String metaDefaultBindingPrefix, final Location location, final boolean ignoreUnmatchedFormal) {
         if (embeddedAssembler.isBound(parameterName))
             return;
 
         embeddedAssembler.setBound(parameterName);
 
-        if (parameterValue.startsWith(InternalConstants.INHERIT_BINDING_PREFIX))
-        {
+        if (parameterValue.startsWith(InternalConstants.INHERIT_BINDING_PREFIX)) {
             String containerParameterName = parameterValue.substring(InternalConstants.INHERIT_BINDING_PREFIX.length());
 
             addInheritedBindingAction(context, parameterName, containerParameterName);
             return;
         }
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 // Because of published parameters, we have to wait until page assembly time to throw out
                 // informal parameters bound to components that don't support informal parameters ...
                 // otherwise we'd throw out (sometimes!) published parameters.
@@ -877,40 +772,48 @@ public class PageLoaderImpl implements P
 
                 // Null meaning an informal parameter and the component (and mixins) doesn't support informals.
 
-                if (binder != null)
-                {
-                    final String defaultBindingPrefix = binder.getDefaultBindingPrefix(metaDefaultBindingPrefix);
+                if (binder == null) {
+                    if (ignoreUnmatchedFormal) {
+                        return;
+                    }
 
-                    InternalComponentResources containerResources = pageAssembly.activeElement.peek()
-                            .getComponentResources();
+                    throw new UnknownValueException(
+                            String.format("Component %s does not include a formal parameter '%s' (and does not support informal parameters).",
+                                    pageAssembly.createdElement.peek().getCompleteId(), parameterName), null,
+                            null,
+                            new AvailableValues("Formal parameters", embeddedAssembler.getFormalParameterNames()));
+                }
 
-                    ComponentPageElement embeddedElement = pageAssembly.createdElement.peek();
-                    InternalComponentResources embeddedResources = embeddedElement.getComponentResources();
+                final String defaultBindingPrefix = binder.getDefaultBindingPrefix(metaDefaultBindingPrefix);
 
-                    Binding binding = elementFactory.newBinding(parameterName, containerResources, embeddedResources,
-                            defaultBindingPrefix, parameterValue, location);
+                InternalComponentResources containerResources = pageAssembly.activeElement.peek()
+                        .getComponentResources();
 
-                    binder.bind(embeddedElement, binding);
-                }
+                ComponentPageElement embeddedElement = pageAssembly.createdElement.peek();
+                InternalComponentResources embeddedResources = embeddedElement.getComponentResources();
+
+                Binding binding = elementFactory.newBinding(parameterName, containerResources, embeddedResources,
+                        defaultBindingPrefix, parameterValue, location);
+
+                binder.bind(embeddedElement, binding);
             }
-        });
+        }
+
+        );
     }
 
     /**
      * Adds a deferred action to the PageAssembly, to handle connecting the embedded components' parameter to the
      * container component's parameter once everything else has been built.
-     * 
+     *
      * @param context
      * @param parameterName
      * @param containerParameterName
      */
     private void addInheritedBindingAction(AssemblerContext context, final String parameterName,
-            final String containerParameterName)
-    {
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+                                           final String containerParameterName) {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 // At the time this action executes, we'll be able to capture the containing and embedded
                 // component. We can then defer the connection logic until after all other construction.
 
@@ -919,10 +822,8 @@ public class PageLoaderImpl implements P
 
                 // Parameters are normally bound bottom to top. Inherited parameters run differently, and should be
                 // top to bottom.
-                pageAssembly.deferred.add(new PageAssemblyAction()
-                {
-                    public void execute(PageAssembly pageAssembly)
-                    {
+                pageAssembly.deferred.add(new PageAssemblyAction() {
+                    public void execute(PageAssembly pageAssembly) {
                         connectInheritedParameter(container, embedded, parameterName, containerParameterName);
                     }
                 });
@@ -931,8 +832,7 @@ public class PageLoaderImpl implements P
     }
 
     private void connectInheritedParameter(ComponentPageElement container, ComponentPageElement embedded,
-            String parameterName, String containerParameterName)
-    {
+                                           String parameterName, String containerParameterName) {
         // TODO: This assumes that the two parameters are both on the core component and not on
         // a mixin. I think this could be improved with more static analysis.
 
@@ -951,13 +851,10 @@ public class PageLoaderImpl implements P
     }
 
     private void addActionForEmbeddedComponent(AssemblerContext context,
-            final EmbeddedComponentAssembler embeddedAssembler, final String embeddedId, final String elementName,
-            final String componentClassName)
-    {
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+                                               final EmbeddedComponentAssembler embeddedAssembler, final String embeddedId, final String elementName,
+                                               final String componentClassName) {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 pageAssembly.checkForRecursion(componentClassName, embeddedAssembler.getLocation());
 
                 ComponentResourceSelector selector = pageAssembly.page.getSelector();
@@ -990,15 +887,13 @@ public class PageLoaderImpl implements P
         });
     }
 
-    private void attribute(AssemblerContext context)
-    {
+    private void attribute(AssemblerContext context) {
         final AttributeToken token = context.next(AttributeToken.class);
 
         String value = token.getValue();
 
         // No expansion makes this easier, more efficient.
-        if (value.indexOf(InternalConstants.EXPANSION_START) < 0)
-        {
+        if (value.indexOf(InternalConstants.EXPANSION_START) < 0) {
             RenderCommand command = new RenderAttribute(token);
 
             context.addComposable(command);
@@ -1006,10 +901,8 @@ public class PageLoaderImpl implements P
             return;
         }
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 InternalComponentResources resources = pageAssembly.activeElement.peek().getComponentResources();
 
                 RenderCommand command = elementFactory.newAttributeElement(resources, token);
@@ -1019,12 +912,9 @@ public class PageLoaderImpl implements P
         });
     }
 
-    private void body(AssemblerContext context)
-    {
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+    private void body(AssemblerContext context) {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 ComponentPageElement element = pageAssembly.activeElement.peek();
 
                 pageAssembly.addRenderCommand(new RenderBodyElement(element));
@@ -1032,14 +922,11 @@ public class PageLoaderImpl implements P
         });
     }
 
-    private void expansion(AssemblerContext context)
-    {
+    private void expansion(AssemblerContext context) {
         final ExpansionToken token = context.next(ExpansionToken.class);
 
-        context.add(new PageAssemblyAction()
-        {
-            public void execute(PageAssembly pageAssembly)
-            {
+        context.add(new PageAssemblyAction() {
+            public void execute(PageAssembly pageAssembly) {
                 ComponentResources resources = pageAssembly.activeElement.peek().getComponentResources();
 
                 RenderCommand command = elementFactory.newExpansionElement(resources, token);
@@ -1049,8 +936,7 @@ public class PageLoaderImpl implements P
         });
     }
 
-    private void text(AssemblerContext context)
-    {
+    private void text(AssemblerContext context) {
         TextToken textToken = context.next(TextToken.class);
 
         context.addComposable(new TextPageElement(textToken.getText()));

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageloadMessages.java Fri Jul  8 17:35:58 2011
@@ -1,4 +1,4 @@
-// Copyright 2009, 2010 The Apache Software Foundation
+// Copyright 2009, 2010, 2011 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -71,11 +71,6 @@ final class PageloadMessages
         return MESSAGES.format("token_not_implemented", type.toString());
     }
 
-    public static String parameterNotSupported(String completeId, String parameterName)
-    {
-        return MESSAGES.format("parameter_not_supported", completeId, parameterName);
-    }
-
     public static String redundantEmbeddedComponentTypes(String embeddedId, String embeddedType, String modelType)
     {
         return MESSAGES.format("redundant_embedded_component_types", embeddedId, embeddedType, modelType);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/pageload/PageloadStrings.properties Fri Jul  8 17:35:58 2011
@@ -1,5 +1,5 @@
 #
-# Copyright 2009, 2010 The Apache Software Foundation
+# Copyright 2009, 2010, 2011 The Apache Software Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ no_more_tokens=No more template tokens.
 could_not_find_override=Could not find an override for extension point '%s'.
 no_parent_for_extension=Component %s uses an extension template, but does not have a parent component.
 token_not_implemented=Not yet implemented: %s
-parameter_not_supported=Component %s does not include a formal parameter '%s' (and does not support informal parameters).
 redundant_embedded_component_types=Embedded component '%s' provides a type attribute in the template ('%s') \
                                    as well as in the component class ('%s'). You should not provide a type attribute \
                                    in the template when defining an embedded component within the component class.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/ParameterTests.groovy Fri Jul  8 17:35:58 2011
@@ -25,7 +25,6 @@ class ParameterTests extends TapestryCor
     /**
      * https://issues.apache.org/jira/browse/TAP5-1227
      */
-
     @Test
     void null_bound_to_primitive_field_is_an_error() {
         openLinks "Null Bound to Primitive Demo"
@@ -33,4 +32,15 @@ class ParameterTests extends TapestryCor
         assertTextPresent "Parameter 'value' of component NullBindingToPrimitive:showint is bound to null. This parameter is not allowed to be null."
     }
 
+   /**
+     * https://issues.apache.org/jira/browse/TAP5-1428
+     */
+    @Test
+    void parameter_specified_with_component_annotation_must_match_a_formal_parameter() {
+        openLinks "Unmatched Formal Parameter with @Component"
+
+        assertTextPresent "Component InvalidFormalParameterDemo:counter does not include a formal parameter 'step' (and does not support informal parameters).",
+                "Formal parameters", "end", "start", "value"
+
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=1144398&r1=1144397&r2=1144398&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Fri Jul  8 17:35:58 2011
@@ -30,26 +30,22 @@ import java.util.List;
 /**
  * Have to start somewhere!
  */
-public class Index
-{
+public class Index {
     @Persist(PersistenceConstants.FLASH)
     private String alert;
 
-    public static class Item implements Comparable<Item>
-    {
+    public static class Item implements Comparable<Item> {
         public final String pageName;
         public final String label;
         public final String description;
 
-        public Item(String pageName, String label, String description)
-        {
+        public Item(String pageName, String label, String description) {
             this.pageName = pageName;
             this.label = label;
             this.description = description;
         }
 
-        public int compareTo(Item o)
-        {
+        public int compareTo(Item o) {
             return label.compareTo(o.label);
         }
     }
@@ -57,6 +53,8 @@ public class Index
     private static final List<Item> ITEMS = CollectionFactory
             .newList(
 
+                    new Item("InvalidFormalParameterDemo", "Unmatched Formal Parameter with @Component", "Parameters specified with @Component annotation must match formal parameters"),
+
                     new Item("NullBindingToPrimitive", "Null Bound to Primitive Demo", "Correct exception when a primitive parameter is bound to null"),
 
                     new Item("TreeDemo", "Tree Component Demo", "Demo of Tree Component"),
@@ -484,8 +482,7 @@ public class Index
 
             );
 
-    static
-    {
+    static {
         Collections.sort(ITEMS);
     }
 
@@ -498,39 +495,32 @@ public class Index
     @Inject
     private ComponentResources resources;
 
-    public List<Item> getItems()
-    {
+    public List<Item> getItems() {
         return ITEMS;
     }
 
-    Object onActionFromSecurePage()
-    {
+    Object onActionFromSecurePage() {
         return securePage.initialize("Triggered from Index");
     }
 
-    public Link getInjectDemoLink()
-    {
+    public Link getInjectDemoLink() {
         return resources.createPageLink(InjectDemo.class, false);
     }
 
-    public List getDemoContext()
-    {
+    public List getDemoContext() {
         return Arrays.asList(1, 2, 3);
     }
 
     /* This will fail, because component classes are not instantiable. */
-    public Object onActionFromInstantiatePage()
-    {
+    public Object onActionFromInstantiatePage() {
         return new Music();
     }
 
-    public void setAlert(String alert)
-    {
+    public void setAlert(String alert) {
         this.alert = alert;
     }
 
-    public String getAlert()
-    {
+    public String getAlert() {
         return alert;
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.java?rev=1144398&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.java Fri Jul  8 17:35:58 2011
@@ -0,0 +1,35 @@
+// 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.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Component;
+import org.apache.tapestry5.integration.app1.components.Count;
+
+/**
+ * @since 5.3
+ */
+public class InvalidFormalParameterDemo {
+
+    // This has to be done using @Component, because non-matching attributes
+    // in the template are quietly dropped. By placing it here, in the @Component annotation,
+    // there's no ambiguity ... the developer expects there to be a parameter with the given name.
+    @Component(parameters = {
+            "start=5",
+            "end=100",
+            "value=var:index",
+            "step=5" // not a formal parameter
+    })
+    private Count counter;
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.tml?rev=1144398&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/InvalidFormalParameterDemo.tml Fri Jul  8 17:35:58 2011
@@ -0,0 +1,11 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
+
+<t:remove>step is not a formal parameter</t:remove>
+<span t:id="counter">
+
+    ... ${var:index}
+
+
+
+</span>
+</html>