Author: hlship
Date: Wed Feb 11 02:22:17 2009
New Revision: 743195

URL: http://svn.apache.org/viewvc?rev=743195&view=rev
Log:
TAP5-165: Components which use PrimaryKeyEncoder should be changed to use 
ValueEncoder, and PrimaryKeyEncoder should be deprecated

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoder.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoderTest.java
Modified:
    tapestry/tapestry5/trunk/src/site/apt/upgrade.apt
    tapestry/tapestry5/trunk/src/site/site.xml
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/PrimaryKeyEncoder.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/DateFieldAjaxFormLoop.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/FormInjectorDemo.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ToDoList.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoderTest.java

Modified: tapestry/tapestry5/trunk/src/site/apt/upgrade.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/upgrade.apt?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/upgrade.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/upgrade.apt Wed Feb 11 02:22:17 2009
@@ -15,6 +15,24 @@
 
 Release 5.1.0.0
 
+* Primary Key Encoder
+
+  <<This is the change between releases that is most likely to affect your 
upgrade.>>
+
+  The 
{{{apidocs/org/apache/tapestry5/PrimaryKeyEncoder.html}PrimaryKeyEncoder}}
+  interface has been deprecated and will be removed in a later release.
+  See   {{{https://issues.apache.org/jira/browse/TAP5-165}TAP5-165}} for the 
rationale.
+
+  You may see type coercion errors on pages where you have specified the 
encoder parameter of
+  the Grid, Loop or AjaxFormLoop components as a PrimaryKeyEncoder.
+  These errors indicate that Tapestry was unable to automatically convert your 
PrimaryKeyEncoder instance into
+  a {{{apidocs/org/apache/tapestry5/ValueEncoder.html}ValueEncoder}}. 
Generally, the only change is to invoke the new constructor for
+  
{{{apdiocs/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.html}DefaultPrimaryKeyEncoder}},
 to identify
+  the type of key used.
+
+  If you don't use DefaultPrimaryKeyEncoder, you will see compile errors about 
the new method, getKeyType().
+  You will have to change your code to implement that new method.
+  
 * Performance Improvements
 
   As part of the changes related to
@@ -28,10 +46,11 @@
 * Tapestry/Spring
 
   There have been some significant changes to the 
{{{tapestry-spring/}tapestry-spring}} module, to
-  support injection of Tapestry services into Springbeans.
+  support injection of Tapestry services into Spring beans. You may find you 
need to add some new configuration
+  to revert to the Tapestry 5.0 behavior.
 
 * Session Persisted Objects
-
+                      
   Tapestry is now more aggressive about automatically re-storing any session 
persisted object
   back into the session at the end of the request (this used to only apply to 
application state objects).  See the 
   {{{guide/persist.html}persistent page data}} notes for more details.
@@ -39,7 +58,8 @@
 * Module Classes
 
   Many questionable practices in Tapestry module classes that used to produce 
warnings
-  have been changed to fail early with exceptions. The rationale is that the 
warnings would be ignored,
+  have been changed to fail early (that is, throw exceptions). The rationale 
is that the warnings
+  are almost always ignored,
   resulting in more difficult to diagnose runtime errors. 
 
   Extra public methods on module classes (methods that do not define services, 
contribute to services,
@@ -47,3 +67,7 @@
 
 
 
+
+
+
+

Modified: tapestry/tapestry5/trunk/src/site/site.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/site.xml?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/trunk/src/site/site.xml Wed Feb 11 02:22:17 2009
@@ -51,7 +51,7 @@
         </menu>
 
         <menu name="Upgrade Notes">
-            <item name="From Tapestry 5" href="upgrade.html"/>
+            <item name="From Tapestry 5.0" href="upgrade.html"/>
             <item name="From Tapestry 4" href="upgrade4.html"/>
             <item name="Upgrade Notes (5.0)" href="upgrade5.0.html"/>
             <item name="Release Notes (5.0)" href="release-notes-5.0.html"/>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-//  Copyright 2008 The Apache Software Foundation
+//  Copyright 2008, 2009 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.
@@ -123,4 +123,13 @@
      * also be visible in the {...@link org.apache.tapestry5.PrimaryKeyEncoder 
encoder parameter}.
      */
     public static final String ADD_ROW = "addRow";
+
+    /**
+     * Event triggered by the {...@link 
org.apache.tapestry5.corelib.components.Loop} component to inform its container 
of
+     * all the values that were supplied from the client during a form 
submission. The event handler method should have
+     * a single parameter, of type Object[] or type List, to receive the 
values.
+     *
+     * @since 5.1.0.0
+     */
+    public static final String SYNCHRONIZE_VALUES = "synchronizeValues";
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/PrimaryKeyEncoder.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/PrimaryKeyEncoder.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/PrimaryKeyEncoder.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/PrimaryKeyEncoder.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2009 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.
@@ -27,6 +27,12 @@
  * @param <K> the type of the primary key, used to identify the value (which 
must be serializable)
  * @param <V> the type of value identified by the key
  * @see org.apache.tapestry5.ValueEncoder
+ * @deprecated This interface overlaps with {...@link 
org.apache.tapestry5.ValueEncoder} and has been deprecated in release
+ *             5.1. The interface itself will be removed in a later release of 
Tapestry. The components that used this
+ *             interface ({...@link 
org.apache.tapestry5.corelib.components.AjaxFormLoop}, {...@link
+ *             org.apache.tapestry5.corelib.components.Grid}, {...@link 
org.apache.tapestry5.corelib.components.GridRows}
+ *             and {...@link org.apache.tapestry5.corelib.components.Loop}) 
have been changed to expect ValueEncoder
+ *             instead, and an automatic coercion from PrimaryKeyEncoder to 
ValueEncoder has been provided.
  */
 public interface PrimaryKeyEncoder<K extends Serializable, V>
 {
@@ -55,4 +61,13 @@
      * @return the value object for the key
      */
     V toValue(K key);
+
+    /**
+     * Returns the type of key. This is primarily used when Tapestry must 
convert an existing PrimaryKeyConverter into a
+     * {...@link org.apache.tapestry5.ValueEncoder}.
+     *
+     * @return key type or null if not known
+     * @since 5.1.0.0
+     */
+    Class<K> getKeyType();
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
 Wed Feb 11 02:22:17 2009
@@ -26,7 +26,6 @@
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.*;
 
-import java.io.Serializable;
 import java.util.Collections;
 import java.util.Iterator;
 
@@ -99,7 +98,7 @@
      * Required parameter used to convert server-side objects (provided from 
the source) into client-side ids and back.
      */
     @Parameter(required = true, allowNull = false)
-    private PrimaryKeyEncoder encoder;
+    private ValueEncoder<Object> encoder;
 
     @InjectComponent
     private ClientElement rowInjector;
@@ -159,11 +158,7 @@
 
         public void addRemoveRowTrigger(String clientId)
         {
-            Serializable id = idForCurrentValue();
-
-            String idType = id.getClass().getName();
-
-            Link link = resources.createEventLink("triggerRemoveRow", id, 
idType);
+            Link link = resources.createEventLink("triggerRemoveRow", 
toClientValue());
 
             String asURI = link.toAbsoluteURI();
 
@@ -184,26 +179,26 @@
 
 
     /**
-     * Action for synchronizing the current element of the loop by recording 
its client value / primary key.
+     * Action for synchronizing the current element of the loop by recording 
its client value.
      */
     static class SyncValue implements ComponentAction<AjaxFormLoop>
     {
-        private final Serializable id;
+        private final String clientValue;
 
-        public SyncValue(Serializable id)
+        public SyncValue(String clientValue)
         {
-            this.id = id;
+            this.clientValue = clientValue;
         }
 
         public void execute(AjaxFormLoop component)
         {
-            component.syncValue(id);
+            component.syncValue(clientValue);
         }
 
         @Override
         public String toString()
         {
-            return String.format("AjaxFormLoop.SyncValue[%s]", id);
+            return String.format("AjaxFormLoop.SyncValue[%s]", clientValue);
         }
     }
 
@@ -274,13 +269,13 @@
 
     @SuppressWarnings({ "unchecked" })
     @Log
-    private void syncValue(Serializable id)
+    private void syncValue(String clientValue)
     {
-        Object value = encoder.toValue(id);
+        Object value = encoder.toValue(clientValue);
 
         if (value == null)
             throw new RuntimeException(
-                    String.format("Unable to convert serialized id '%s' back 
into an object.", id));
+                    String.format("Unable to convert client value '%s' back 
into a server-side object.", clientValue));
 
         this.value = value;
     }
@@ -296,21 +291,22 @@
 
     private void syncCurrentValue()
     {
-        Serializable id = idForCurrentValue();
+        String id = toClientValue();
 
-        // Add the command that restores value from the value id,
+        // Add the command that restores value from the value clientValue,
         // when the form is submitted.
 
         formSupport.store(this, new SyncValue(id));
     }
 
     /**
-     * Uses the {...@link org.apache.tapestry5.PrimaryKeyEncoder} to convert 
the current row value to an id.
+     * Uses the {...@link org.apache.tapestry5.ValueEncoder} to convert the 
current server-side value to a client-side
+     * value.
      */
     @SuppressWarnings({ "unchecked" })
-    private Serializable idForCurrentValue()
+    private String toClientValue()
     {
-        return encoder.toKey(value);
+        return encoder.toClient(value);
     }
 
 
@@ -396,8 +392,7 @@
         if (value == null)
             throw new IllegalArgumentException(
                     String.format("Event handler for event 'addRow' from %s 
should have returned a non-null value.",
-                                  resources.getCompleteId())
-            );
+                                  resources.getCompleteId()));
 
 
         renderingInjector = true;
@@ -418,13 +413,9 @@
     }
 
     @Log
-    Object onTriggerRemoveRow(String rowId, String idTypeName)
+    Object onTriggerRemoveRow(String rowId)
     {
-        Class idType = componentClassCache.forName(idTypeName);
-
-        Serializable coerced = (Serializable) typeCoercer.coerce(rowId, 
idType);
-
-        Object value = encoder.toValue(coerced);
+        Object value = encoder.toValue(rowId);
 
         resources.triggerEvent(EventConstants.REMOVE_ROW, new Object[] { value 
}, null);
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2009 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.
@@ -26,10 +26,7 @@
 import org.apache.tapestry5.internal.services.ClientBehaviorSupport;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.internal.util.Defense;
-import org.apache.tapestry5.services.BeanModelSource;
-import org.apache.tapestry5.services.ComponentEventResultProcessor;
-import org.apache.tapestry5.services.FormSupport;
-import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.*;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -88,7 +85,7 @@
      * provided to override the default cell renderer for a particular column 
... the components within the block can
      * use the property bound to the row parameter to know what they should 
render.
      */
-    @Parameter
+    @Parameter(principal = true)
     private Object row;
 
     /**
@@ -206,12 +203,12 @@
     private boolean inPlace;
 
     /**
-     * Changes how state is recorded into the form to store the {...@linkplain 
org.apache.tapestry5.PrimaryKeyEncoder#toKey(Object)
-     * primary key} for each row (rather than the index), and restore the 
{...@linkplain
-     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable) 
row values} from the primary keys.
+     * Changes how state is recorded into the form to store the {...@linkplain 
org.apache.tapestry5.ValueEncoder#toClient(Object)
+     * client value} for each row (rather than the index), and restore the 
{...@linkplain
+     * org.apache.tapestry5.ValueEncoder#toValue(String)row values} from the 
client value.
      */
     @Parameter
-    private PrimaryKeyEncoder encoder;
+    private ValueEncoder encoder;
 
     /**
      * The name of the psuedo-zone that encloses the Grid.
@@ -245,7 +242,7 @@
                     "index=inherit:columnIndex",
                     "lean=inherit:lean",
                     "overrides=overrides",
-                    "zone=zone"})
+                    "zone=zone" })
     private GridColumns columns;
 
     @Component(
@@ -259,14 +256,14 @@
                     "overrides=overrides",
                     "volatile=inherit:volatile",
                     "encoder=inherit:encoder",
-                    "lean=inherit:lean"})
+                    "lean=inherit:lean" })
     private GridRows rows;
 
     @Component(parameters = {
             "source=dataSource",
             "rowsPerPage=rowsPerPage",
             "currentPage=currentPage",
-            "zone=zone"})
+            "zone=zone" })
     private GridPager pager;
 
     @Component(parameters = "to=pagerTop")
@@ -301,6 +298,14 @@
     @Environmental
     private ComponentEventResultProcessor componentEventResultProcessor;
 
+    @Inject
+    private ComponentDefaultProvider defaultsProvider;
+
+    ValueEncoder defaultEncoder()
+    {
+        return defaultsProvider.defaultValueEncoder("row", resources);
+    }
+
     /**
      * A version of GridDataSource that caches the availableRows property. 
This addresses TAPESTRY-2245.
      */

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/GridRows.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2009 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.
@@ -28,8 +28,8 @@
 package org.apache.tapestry5.corelib.components;
 
 import org.apache.tapestry5.ComponentAction;
-import org.apache.tapestry5.PrimaryKeyEncoder;
 import org.apache.tapestry5.PropertyOverrides;
+import org.apache.tapestry5.ValueEncoder;
 import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.annotations.Parameter;
 import org.apache.tapestry5.annotations.Property;
@@ -41,7 +41,6 @@
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.services.FormSupport;
 
-import java.io.Serializable;
 import java.util.List;
 
 /**
@@ -52,7 +51,7 @@
  * form render and the form submission, this can cause unexpected results, 
including applying changes to the wrong
  * objects.
  */
-...@suppresswarnings({"unchecked"})
+...@suppresswarnings({ "unchecked" })
 public class GridRows
 {
     private int startRow;
@@ -87,52 +86,26 @@
     }
 
     /**
-     * This action is used when a {...@link 
org.apache.tapestry5.PrimaryKeyEncoder} is provided.
+     * This action is used when a {...@link org.apache.tapestry5.ValueEncoder} 
is provided.
      */
-    static class SetupForRowByKey implements ComponentAction<GridRows>
+    static class SetupForRowWithClientValue implements 
ComponentAction<GridRows>
     {
-        private final Serializable rowKey;
+        private final String clientValue;
 
-        SetupForRowByKey(Serializable rowKey)
+        SetupForRowWithClientValue(String clientValue)
         {
-            this.rowKey = rowKey;
+            this.clientValue = clientValue;
         }
 
         public void execute(GridRows component)
         {
-            component.setupForRowByKey(rowKey);
+            component.setupForRowWithClientValue(clientValue);
         }
 
         @Override
         public String toString()
         {
-            return String.format("GridRows.SetupForRowByKey[%s]", rowKey);
-        }
-    }
-
-
-    /**
-     * This action is also associated with the {...@link 
org.apache.tapestry5.PrimaryKeyEncoder}; it allows the PKE to be
-     * informed of the series of keys to expect with the form submission.
-     */
-    static class PrepareForKeys implements ComponentAction<GridRows>
-    {
-        private List<Serializable> storedKeys;
-
-        public PrepareForKeys(List<Serializable> storedKeys)
-        {
-            this.storedKeys = storedKeys;
-        }
-
-        public void execute(GridRows component)
-        {
-            component.prepareForKeys(storedKeys);
-        }
-
-        @Override
-        public String toString()
-        {
-            return "GridRows.PrepareForKeys" + storedKeys.toString();
+            return String.format("GridRows.SetupForRowWithClientValue[%s]", 
clientValue);
         }
     }
 
@@ -192,12 +165,13 @@
     private boolean volatileState;
 
     /**
-     * Changes how state is recorded into the form to store the {...@linkplain 
org.apache.tapestry5.PrimaryKeyEncoder#toKey(Object)
-     * primary key} for each row (rather than the index), and restore the 
{...@linkplain
-     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable) 
row values} from the primary keys.
+     * Changes how state is recorded into the form to store the {...@linkplain 
org.apache.tapestry5.ValueEncoder#toClient(Object)
+     * client value} for each row (rather than the index), and restore the 
{...@linkplain
+     * org.apache.tapestry5.ValueEncoder#toValue(String) row values} from the 
client value.
      */
     @Parameter
-    private PrimaryKeyEncoder encoder;
+    private ValueEncoder encoder;
+
 
     /**
      * Optional output parameter (only set during rendering) that identifies 
the current row index. This is the index on
@@ -230,8 +204,6 @@
     @Property(write = false)
     private PropertyModel columnModel;
 
-    private List<Serializable> encodedPrimaryKeys;
-
     public String getRowClass()
     {
         List<String> classes = CollectionFactory.newList();
@@ -298,16 +270,6 @@
 
         recordStateByIndex = recordingStateInsideForm && (encoder == null);
         recordStateByEncoder = recordingStateInsideForm && (encoder != null);
-
-        if (recordStateByEncoder)
-        {
-            encodedPrimaryKeys = CollectionFactory.newList();
-
-            // As we render, we'll fill in encodedPrimaryKeys.  That's ok, 
because nothing is serialized
-            // until later.  When the form is submitted, this will give us a 
chance to inform
-            // the PKE about the keys to expect.
-            formSupport.store(this, new PrepareForKeys(encodedPrimaryKeys));
-        }
     }
 
     /**
@@ -320,24 +282,15 @@
 
     /**
      * Callback method that bypasses the data source and converts a primary 
key back into a row value (via {...@link
-     * org.apache.tapestry5.PrimaryKeyEncoder#toValue(java.io.Serializable)}).
+     * org.apache.tapestry5.ValueEncoder#toValue(String)}).
      */
-    void setupForRowByKey(Serializable rowKey)
+    void setupForRowWithClientValue(String clientValue)
     {
-        row = encoder.toValue(rowKey);
+        row = encoder.toValue(clientValue);
 
         if (row == null)
             throw new IllegalArgumentException(
-                    String.format("%s returned null for key %s.", encoder, 
rowKey));
-    }
-
-    /**
-     * Callback method that allows the primary key encoder to prepare for the 
keys that will be resolved to row values
-     * in this request.
-     */
-    private void prepareForKeys(List<Serializable> storedKeys)
-    {
-        encoder.prepareForKeys(storedKeys);
+                    String.format("%s returned null for client value '%s'.", 
encoder, clientValue));
     }
 
 
@@ -360,10 +313,8 @@
 
             if (recordStateByEncoder)
             {
-                Serializable key = encoder.toKey(row);
-                encodedPrimaryKeys.add(key);
-
-                formSupport.store(this, new SetupForRowByKey(key));
+                String key = encoder.toClient(row);
+                formSupport.store(this, new SetupForRowWithClientValue(key));
             }
         }
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Loop.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009 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.
@@ -18,6 +18,7 @@
 import org.apache.tapestry5.annotations.*;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.ComponentDefaultProvider;
 import org.apache.tapestry5.services.FormSupport;
 import org.apache.tapestry5.services.Heartbeat;
 
@@ -32,6 +33,9 @@
  * For a non-volatile Loop inside the form, the Loop stores a series of 
commands that start and end heartbeats and store
  * state (either as full objects when there the encoder parameter is not 
bound, or as client-side objects when there is
  * an encoder).
+ * <p/>
+ * When the Loop is used inside a Form, it will generate an {...@link 
org.apache.tapestry5.EventConstants#SYNCHRONIZE_VALUES}
+ * event to inform its container what values were submitted and in what order.
  */
 @SupportsInformalParameters
 public class Loop
@@ -144,57 +148,58 @@
     /**
      * Restores the value using a stored primary key via {...@link 
PrimaryKeyEncoder#toValue(Serializable)}.
      */
-    static class RestoreStateViaEncodedPrimaryKey implements 
ComponentAction<Loop>
+    static class RestoreStateFromStoredClientValue implements 
ComponentAction<Loop>
     {
-        private static final long serialVersionUID = -2422790241589517336L;
+        private final String clientValue;
 
-        private final Serializable primaryKey;
-
-        public RestoreStateViaEncodedPrimaryKey(final Serializable primaryKey)
+        public RestoreStateFromStoredClientValue(final String clientValue)
         {
-            this.primaryKey = primaryKey;
+            this.clientValue = clientValue;
         }
 
         public void execute(Loop component)
         {
-            component.restoreStateViaEncodedPrimaryKey(primaryKey);
+            component.restoreStateFromStoredClientValue(clientValue);
         }
 
         @Override
         public String toString()
         {
-            return String.format("Loop.RestoreStateViaEncodedPrimaryKey[%s]", 
primaryKey);
+            return String.format("Loop.RestoreStateFromStoredClientValue[%s]", 
clientValue);
         }
     }
 
     /**
-     * Stores a list of keys to be passed to {...@link 
PrimaryKeyEncoder#prepareForKeys(List)}.
+     * Start of processing event that allows the Loop to set up internal 
bookeeping, to track which values have come up
+     * in the form submission.
      */
-    static class PrepareForKeys implements ComponentAction<Loop>
+    static final ComponentAction<Loop> PREPARE_FOR_SUBMISSION = new 
ComponentAction<Loop>()
     {
-        private static final long serialVersionUID = -6515255627142956828L;
-
-        /**
-         * The variable is final, the contents are mutable while the Loop 
renders.
-         */
-        private final List<Serializable> keys;
+        public void execute(Loop component)
+        {
+            component.prepareForSubmission();
+        }
 
-        public PrepareForKeys(final List<Serializable> keys)
+        @Override
+        public String toString()
         {
-            this.keys = keys;
+            return "Loop.PrepareForSubmission";
         }
+    };
 
+    static final ComponentAction<Loop> NOTIFY_CONTAINER = new 
ComponentAction<Loop>()
+    {
         public void execute(Loop component)
         {
-            component.prepareForKeys(keys);
+            component.notifyContainer();
         }
 
         @Override
         public String toString()
         {
-            return "Loop.PrepareForKeys" + keys;
+            return "Loop.NotifyContainer";
         }
-    }
+    };
 
     /**
      * Defines the collection of values for the loop to iterate over. If not 
specified, defaults to a property of the
@@ -204,11 +209,12 @@
     private Iterable<?> source;
 
     /**
-     * Optional primary key converter; if provided and inside a form and not 
volatile, then each iterated value is
-     * converted and stored into the form.
+     * Optional value converter; if provided (or defaulted) and inside a form 
and not volatile, then each iterated value
+     * is converted and stored into the form. A default for this is calculated 
from the type of the property bound to
+     * the value parameter.
      */
     @Parameter
-    private PrimaryKeyEncoder<Serializable, Object> encoder;
+    private ValueEncoder<Object> encoder;
 
     /**
      * If true and the Loop is enclosed by a Form, then the normal state 
saving logic is turned off. Defaults to false,
@@ -230,7 +236,7 @@
     /**
      * The current value, set before the component renders its body.
      */
-    @Parameter
+    @Parameter(principal = true)
     private Object value;
 
     /**
@@ -255,14 +261,28 @@
     @Inject
     private ComponentResources resources;
 
+    @Inject
+    private ComponentDefaultProvider defaultProvider;
+
     private Block cleanupBlock;
 
+    /**
+     * Objects that have been recovered via {...@link 
org.apache.tapestry5.ValueEncoder#toValue(String)} during the
+     * processing of the loop. These are sent to the container via an event.
+     */
+    private List<Object> synchonizedValues;
+
 
     String defaultElement()
     {
         return resources.getElementName();
     }
 
+    ValueEncoder defaultEncoder()
+    {
+        return defaultProvider.defaultValueEncoder("value", resources);
+    }
+
     @SetupRender
     boolean setup()
     {
@@ -272,6 +292,9 @@
 
         storeRenderStateInForm = formSupport != null && !volatileState;
 
+        if (storeRenderStateInForm)
+            formSupport.store(this, PREPARE_FOR_SUBMISSION);
+
         // Only render the body if there is something to iterate over
 
         boolean hasContent = iterator != null && iterator.hasNext();
@@ -279,16 +302,6 @@
         if (formSupport != null && hasContent)
         {
             formSupport.store(this, volatileState ? SETUP_FOR_VOLATILE : 
RESET_INDEX);
-
-            if (encoder != null)
-            {
-                List<Serializable> keyList = CollectionFactory.newList();
-
-                // We'll keep updating the _keyList while the Loop renders, 
the values will "lock
-                // down" when the Form serializes all the data.
-
-                formSupport.store(this, new PrepareForKeys(keyList));
-            }
         }
 
         cleanupBlock = hasContent ? null : empty;
@@ -298,21 +311,17 @@
         return hasContent;
     }
 
+
     /**
      * Returns the empty block, or null, after the render has finished. It 
will only be the empty block (which itself
      * may be null) if the source was null or empty.
      */
     Block cleanupRender()
     {
-        return cleanupBlock;
-    }
-
-    private void prepareForKeys(List<Serializable> keys)
-    {
-        // Again, the encoder existed when we rendered, we better have another 
available
-        // when the enclosing Form is submitted.
+        if (storeRenderStateInForm)
+            formSupport.store(this, NOTIFY_CONTAINER);
 
-        encoder.prepareForKeys(keys);
+        return cleanupBlock;
     }
 
     private void setupForVolatile()
@@ -344,8 +353,9 @@
             }
             else
             {
-                Serializable primaryKey = encoder.toKey(value);
-                formSupport.store(this, new 
RestoreStateViaEncodedPrimaryKey(primaryKey));
+                String clientValue = encoder.toClient(value);
+
+                formSupport.store(this, new 
RestoreStateFromStoredClientValue(clientValue));
             }
         }
 
@@ -405,14 +415,28 @@
     /**
      * Restores state previously encoded by the Loop and stored into the Form.
      */
-    private void restoreStateViaEncodedPrimaryKey(Serializable primaryKey)
+    private void restoreStateFromStoredClientValue(String clientValue)
     {
-        // We assume that if a encoder is available when we rendered, that one 
will be available
-        // when the form is submitted. TODO: Check for this.
+        // We assume that if an encoder is available when we rendered, that 
one will be available
+        // when the form is submitted.
 
-        Object restoredValue = encoder.toValue(primaryKey);
+        Object restoredValue = encoder.toValue(clientValue);
 
         restoreState(restoredValue);
+
+        synchonizedValues.add(restoredValue);
+    }
+
+    private void prepareForSubmission()
+    {
+        synchonizedValues = CollectionFactory.newList();
+    }
+
+    private void notifyContainer()
+    {
+        Object[] values = synchonizedValues.toArray();
+
+        resources.triggerEvent(EventConstants.SYNCHRONIZE_VALUES, values, 
null);
     }
 
     // For testing:

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoder.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoder.java?rev=743195&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoder.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoder.java
 Wed Feb 11 02:22:17 2009
@@ -0,0 +1,84 @@
+// Copyright 2009 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.util;
+
+import org.apache.tapestry5.PrimaryKeyEncoder;
+import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.util.DefaultPrimaryKeyEncoder;
+
+import java.io.Serializable;
+
+/**
+ * This is a key part of the plan to eliminate {...@link 
org.apache.tapestry5.PrimaryKeyEncoder}.
+ *
+ * @since 5.1.0.0
+ */
+...@suppresswarnings({ "unchecked" })
+public class PrimaryKeyEncoder2ValueEncoder implements 
Coercion<PrimaryKeyEncoder, ValueEncoder>
+{
+    // The magic of proxies: a coercion within TypeCoercer can use TypeCoercer 
as part of its job!
+    private final TypeCoercer coercer;
+
+    public PrimaryKeyEncoder2ValueEncoder(TypeCoercer coercer)
+    {
+        this.coercer = coercer;
+    }
+
+    public ValueEncoder coerce(final PrimaryKeyEncoder input)
+    {
+        final Class keyType = input.getKeyType();
+
+        if (keyType == null)
+        {
+            String message = String.format("Unable to extract primary key type 
from %s. " +
+                    "This represents a change from Tapestry 5.0 to Tapestry 
5.1.", input);
+
+            if (input instanceof DefaultPrimaryKeyEncoder)
+                message +=
+                        " Class DefaultPrimaryKeyEncoder now includes a 
constructor for specifying the key type. " +
+                                "You should change the code that instantiates 
the encoder.";
+            else
+                message += " You should ensure that the getKeyType() method 
returns the correct Class.";
+
+            throw new RuntimeException(message);
+        }
+
+        return new ValueEncoder()
+        {
+            public String toClient(Object value)
+            {
+                Object key = input.toKey(value);
+
+                return coercer.coerce(key, String.class);
+            }
+
+            public Object toValue(String clientValue)
+            {
+                Serializable key = (Serializable) coercer.coerce(clientValue, 
keyType);
+
+                return input.toValue(key);
+            }
+
+            @Override
+            public String toString()
+            {
+                return String.format("<ValueEncoder coercion wrapper around 
PrimaryKeyEncoder[%s]>",
+                                     keyType.getName());
+            }
+        };
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
 Wed Feb 11 02:22:17 2009
@@ -32,6 +32,7 @@
 import org.apache.tapestry5.internal.services.*;
 import org.apache.tapestry5.internal.transform.*;
 import org.apache.tapestry5.internal.translator.*;
+import org.apache.tapestry5.internal.util.PrimaryKeyEncoder2ValueEncoder;
 import org.apache.tapestry5.internal.util.RenderableAsBlock;
 import org.apache.tapestry5.internal.util.StringRenderable;
 import org.apache.tapestry5.ioc.*;
@@ -802,10 +803,10 @@
      * component) to {...@link org.apache.tapestry5.ComponentResources} 
<li>String to {...@link
      * org.apache.tapestry5.corelib.data.BlankOption} <li> {...@link 
org.apache.tapestry5.ComponentResources} to {...@link
      * org.apache.tapestry5.PropertyOverrides} <li>String to {...@link 
org.apache.tapestry5.Renderable} <li>{...@link
-     * org.apache.tapestry5.Renderable} to {...@link 
org.apache.tapestry5.Block} <li>String to {...@link
-     * java.text.DateFormat}</ul>
+     * org.apache.tapestry5.Renderable} to {...@link 
org.apache.tapestry5.Block} <li>String to {...@link java.text.DateFormat}
+     * <li>{...@link org.apache.tapestry5.PrimaryKeyEncoder} to {...@link 
org.apache.tapestry5.ValueEncoder}</ul>
      */
-    public static void contributeTypeCoercer(Configuration<CoercionTuple> 
configuration)
+    public static void contributeTypeCoercer(Configuration<CoercionTuple> 
configuration, @Builtin TypeCoercer coercer)
     {
         add(configuration, ComponentResources.class, PropertyOverrides.class,
             new Coercion<ComponentResources, PropertyOverrides>()
@@ -908,6 +909,8 @@
                 return new SimpleDateFormat(input);
             }
         });
+
+        add(configuration, PrimaryKeyEncoder.class, ValueEncoder.class, new 
PrimaryKeyEncoder2ValueEncoder(coercer));
     }
 
     /**
@@ -1026,7 +1029,7 @@
                                                                   
UpdateListenerHub updateListenerHub,
 
                                                                   
@ClasspathProvider AssetFactory classpathAssetFactory,
-                                                                  
+
                                                                   
ClasspathURLConverter classpathURLConverter)
     {
         ValidationMessagesSourceImpl service = new 
ValidationMessagesSourceImpl(configuration,

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoder.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2009 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.
@@ -32,6 +32,7 @@
  *
  * @param <K> the key type (which must be serializable)
  * @param <V> the value type
+ * @deprecated See deprecation notes for {...@link 
org.apache.tapestry5.PrimaryKeyEncoder}.
  */
 public class DefaultPrimaryKeyEncoder<K extends Serializable, V> implements 
PrimaryKeyEncoder<K, V>
 {
@@ -43,6 +44,31 @@
 
     private K currentKey;
 
+    private final Class<K> keyType;
+
+    /**
+     * Compatibility with 5.0: new encoder, key type unknown. You 
<em>will</em> want to use the other constructor and
+     * specify the key type.
+     */
+    public DefaultPrimaryKeyEncoder()
+    {
+        this(null);
+    }
+
+    /**
+     * @since 5.1.0.0
+     */
+    public DefaultPrimaryKeyEncoder(Class<K> keyType)
+    {
+        this.keyType = keyType;
+    }
+
+
+    public Class<K> getKeyType()
+    {
+        return keyType;
+    }
+
     /**
      * Adds a new key/value pair to the encoder.
      */

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml 
(original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/GridFormEncoderDemo.tml 
Wed Feb 11 02:22:17 2009
@@ -9,7 +9,6 @@
         <t:errors/>
 
         <table t:id="grid" t:type="Grid" source="items" row="item" 
pagerposition="top"
-               encoder="encoder"
                add="id" reorder="id,title,urgency"
                rowsperpage="5">
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/DateFieldAjaxFormLoop.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/DateFieldAjaxFormLoop.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/DateFieldAjaxFormLoop.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/DateFieldAjaxFormLoop.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-//  Copyright 2008 The Apache Software Foundation
+//  Copyright 2008, 2009 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.
@@ -45,7 +45,6 @@
     {
         List<DateHolder> result = CollectionFactory.newList(database.values());
 
-
         Collections.sort(result, new Comparator<DateHolder>()
         {
             public int compare(DateHolder o1, DateHolder o2)
@@ -59,7 +58,8 @@
 
     public PrimaryKeyEncoder<Integer, DateHolder> getDateHolderConverter()
     {
-        DefaultPrimaryKeyEncoder<Integer, DateHolder> result = new 
DefaultPrimaryKeyEncoder<Integer, DateHolder>();
+        DefaultPrimaryKeyEncoder<Integer, DateHolder> result =
+                new DefaultPrimaryKeyEncoder<Integer, 
DateHolder>(Integer.class);
 
         for (DateHolder dh : getDateHolders())
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/FormInjectorDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/FormInjectorDemo.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/FormInjectorDemo.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/FormInjectorDemo.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 2008, 2009 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.
@@ -68,6 +68,11 @@
             {
                 return DB.get(key);
             }
+
+            public Class<Long> getKeyType()
+            {
+                return Long.class;
+            }
         };
     }
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridFormEncoderDemo.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-//  Copyright 2008 The Apache Software Foundation
+//  Copyright 2008, 2009 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,11 +14,8 @@
 
 package org.apache.tapestry5.integration.app1.pages;
 
-import org.apache.tapestry5.PrimaryKeyEncoder;
 import org.apache.tapestry5.annotations.InjectComponent;
 import org.apache.tapestry5.corelib.components.Grid;
-import org.apache.tapestry5.integration.app1.data.ToDoItem;
-import org.apache.tapestry5.util.DefaultPrimaryKeyEncoder;
 
 public class GridFormEncoderDemo extends GridFormDemo
 {
@@ -31,15 +28,4 @@
             grid.getSortModel().updateSort("title");
     }
 
-    public PrimaryKeyEncoder<Long, ToDoItem> getEncoder()
-    {
-        DefaultPrimaryKeyEncoder<Long, ToDoItem> result = new 
DefaultPrimaryKeyEncoder<Long, ToDoItem>();
-
-        for (ToDoItem item : getItems())
-        {
-            result.add(item.getId(), item);
-        }
-
-        return result;
-    }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ToDoList.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ToDoList.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ToDoList.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ToDoList.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2009 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.
@@ -65,7 +65,7 @@
     {
         List<ToDoItem> items = database.findAll();
 
-        encoder = new DefaultPrimaryKeyEncoder<Long, ToDoItem>();
+        encoder = new DefaultPrimaryKeyEncoder<Long, ToDoItem>(long.class);
 
         for (ToDoItem item : items)
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
 Wed Feb 11 02:22:17 2009
@@ -16,6 +16,7 @@
 
 import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.integration.app1.data.ToDoItem;
 import org.apache.tapestry5.integration.app1.data.Track;
 import org.apache.tapestry5.internal.services.GenericValueEncoderFactory;
 import org.apache.tapestry5.ioc.Configuration;
@@ -206,9 +207,10 @@
     }
 
     public static void contributeValueEncoderSource(MappedConfiguration<Class, 
ValueEncoderFactory> configuration,
-                                                    final MusicLibrary library)
+                                                    final MusicLibrary library,
+                                                    final ToDoDatabase 
todoDatabase)
     {
-        ValueEncoder<Track> encoder = new ValueEncoder<Track>()
+        ValueEncoder<Track> trackEncoder = new ValueEncoder<Track>()
         {
             public String toClient(Track value)
             {
@@ -224,7 +226,24 @@
         };
 
 
-        configuration.add(Track.class, 
GenericValueEncoderFactory.create(encoder));
+        configuration.add(Track.class, 
GenericValueEncoderFactory.create(trackEncoder));
+
+        ValueEncoder<ToDoItem> todoEncoder = new ValueEncoder<ToDoItem>()
+        {
+            public String toClient(ToDoItem value)
+            {
+                return String.valueOf(value.getId());
+            }
+
+            public ToDoItem toValue(String clientValue)
+            {
+                long id = Long.parseLong(clientValue);
+
+                return todoDatabase.get(id);
+            }
+        };
+
+        configuration.add(ToDoItem.class, 
GenericValueEncoderFactory.create(todoEncoder));
     }
 
 

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoderTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoderTest.java?rev=743195&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoderTest.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/util/PrimaryKeyEncoder2ValueEncoderTest.java
 Wed Feb 11 02:22:17 2009
@@ -0,0 +1,125 @@
+// Copyright 2009 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.util;
+
+import org.apache.tapestry5.PrimaryKeyEncoder;
+import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.internal.test.InternalBaseTestCase;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.util.DefaultPrimaryKeyEncoder;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class PrimaryKeyEncoder2ValueEncoderTest extends InternalBaseTestCase
+{
+
+    private PrimaryKeyEncoder2ValueEncoder coercion;
+
+    @BeforeClass
+    public void setup()
+    {
+        TypeCoercer coercer = getService(TypeCoercer.class);
+
+        coercion = new PrimaryKeyEncoder2ValueEncoder(coercer);
+    }
+
+    @Test
+    public void key_type_is_known()
+    {
+        PrimaryKeyEncoder pke = newMock(PrimaryKeyEncoder.class);
+
+        Object value = new Object();
+        Long primaryKey = new Long(99);
+
+        expect(pke.getKeyType()).andReturn(Long.class);
+
+        expect(pke.toKey(value)).andReturn(primaryKey);
+
+        expect(pke.toValue(primaryKey)).andReturn(value);
+
+        replay();
+
+        ValueEncoder ve = coercion.coerce(pke);
+
+        assertEquals(ve.toClient(value), "99");
+        assertEquals(ve.toValue("99"), value);
+
+        verify();
+    }
+
+    @Test
+    public void unknown_key_type()
+    {
+        PrimaryKeyEncoder pke = new PrimaryKeyEncoder()
+        {
+            public Serializable toKey(Object value)
+            {
+                return null;
+            }
+
+            public void prepareForKeys(List keys)
+            {
+            }
+
+            public Object toValue(Serializable key)
+            {
+                return null;
+            }
+
+            public Class getKeyType()
+            {
+                return null;
+            }
+
+            @Override
+            public String toString()
+            {
+                return "<Dummy>";
+            }
+        };
+
+        try
+        {
+            coercion.coerce(pke);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertMessageContains(ex,
+                                  "Unable to extract primary key type from 
<Dummy>.",
+                                  "You should ensure that the getKeyType() 
method returns the correct Class.");
+        }
+    }
+
+    @Test
+    public void unknown_key_type_for_default_pke()
+    {
+        try
+        {
+            coercion.coerce(new DefaultPrimaryKeyEncoder());
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertMessageContains(ex,
+                                  "Class DefaultPrimaryKeyEncoder now includes 
a constructor for specifying the key type.");
+        }
+    }
+
+
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoderTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoderTest.java?rev=743195&r1=743194&r2=743195&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoderTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/util/DefaultPrimaryKeyEncoderTest.java
 Wed Feb 11 02:22:17 2009
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2009 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.
@@ -23,11 +23,12 @@
 {
     static class IntStringEncoder extends DefaultPrimaryKeyEncoder<Integer, 
String>
     {
-
+        public IntStringEncoder()
+        {
+            super(Integer.class);
+        }
     }
 
-    ;
-
     private final int FRED_ID = 1;
 
     private final String FRED = "FRED";


Reply via email to