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 2008/01/18 01:52:59 UTC

svn commit: r613029 - in /tapestry/tapestry5/trunk: tapestry-core/src/main/java/org/apache/tapestry/ tapestry-core/src/main/java/org/apache/tapestry/corelib/base/ tapestry-core/src/main/java/org/apache/tapestry/internal/ tapestry-core/src/main/java/org...

Author: hlship
Date: Thu Jan 17 16:52:51 2008
New Revision: 613029

URL: http://svn.apache.org/viewvc?rev=613029&view=rev
Log:
TAPESTRY-2056: Add configurable null handling for text fields

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/FieldValidationSupport.java
      - copied, changed from r612958, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/FieldValidationSupport.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/NullFieldStrategy.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultNullFieldStrategy.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/ZeroNullFieldStrategy.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/NullFieldStrategyBindingFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/NullFieldStrategySource.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/NullStrategyDemo.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImplTest.java
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/FieldValidationSupport.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Translator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Validator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/FieldValidationSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/FieldValidationSupportImplTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/coerce.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/resources/images/type-coercer.png
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java
    tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java
    tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry/upload/components/UploadTest.java

Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/FieldValidationSupport.java (from r612958, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/FieldValidationSupport.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/FieldValidationSupport.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/FieldValidationSupport.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/FieldValidationSupport.java&r1=612958&r2=613029&rev=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/FieldValidationSupport.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/FieldValidationSupport.java Thu Jan 17 16:52:51 2008
@@ -12,12 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-import org.apache.tapestry.ComponentResources;
-import org.apache.tapestry.FieldValidator;
-import org.apache.tapestry.Translator;
-import org.apache.tapestry.ValidationException;
+package org.apache.tapestry;
 
 /**
  * Services to help with field {@linkplain org.apache.tapestry.Validator validation} and {@linkplain
@@ -35,6 +30,7 @@
      * @param componentResources used to fire events on the component
      * @param translator         used if the component does not provide a non-null value
      * @return the translated value  or null if the value is null
+     * @see org.apache.tapestry.Translator#toClient(Object)
      */
     String toClient(Object value, ComponentResources componentResources, Translator translator);
 
@@ -51,6 +47,7 @@
      * @return the input parsed to an object
      * @throws org.apache.tapestry.ValidationException
      *          if the value can't be parsed
+     * @see org.apache.tapestry.Translator#parseClient(String, org.apache.tapestry.ioc.Messages)
      */
     Object parseClient(String clientValue, ComponentResources componentResources, Translator translator)
             throws ValidationException;
@@ -63,6 +60,7 @@
      * @param componentResources used to trigger events
      * @param validator          performs normal validations
      * @throws ValidationException if the value is not valid
+     * @see org.apache.tapestry.Validator#validate(Field, Object, org.apache.tapestry.ioc.MessageFormatter, Object)
      */
     void validate(Object value, ComponentResources componentResources, FieldValidator validator)
             throws ValidationException;

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/NullFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/NullFieldStrategy.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/NullFieldStrategy.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/NullFieldStrategy.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,40 @@
+// Copyright  2008 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.tapestry;
+
+
+/**
+ * Defines a strategy, used by {@link Field} components such as {@link org.apache.tapestry.corelib.components.TextField},
+ * to handle the case where either the server-side value to be sent (as a string) to the client, or the client-side
+ * string passed back up to the server, is null or blank.
+ *
+ * @see org.apache.tapestry.services.NullFieldStrategySource
+ */
+public interface NullFieldStrategy
+{
+    /**
+     * Provides a replacement value for null, when converting the server-side object to a client-side string. The
+     * replacement value will be passed to {@link FieldValidationSupport#toClient(Object, ComponentResources,
+     * Translator)}.
+     */
+    Object replaceToClient();
+
+    /**
+     * Provides a replacement value for a null or blank string passed from the client to the server as part of a form
+     * submission. This replacement value will be passed to {@link FieldValidationSupport#parseClient(String,
+     * ComponentResources, Translator)} as if it were the value supplied by the user.
+     */
+    String replaceFromClient();
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Translator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Translator.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Translator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Translator.java Thu Jan 17 16:52:51 2008
@@ -22,7 +22,7 @@
  *
  * @param <T>
  * @see org.apache.tapestry.services.TranslatorDefaultSource
- * @see org.apache.tapestry.services.FieldValidationSupport
+ * @see FieldValidationSupport
  */
 public interface Translator<T>
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Validator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Validator.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Validator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/Validator.java Thu Jan 17 16:52:51 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -19,35 +19,33 @@
 import org.apache.tapestry.services.ValidationMessagesSource;
 
 /**
- * Used by a {@link Field} to enforce a <strong>constraint</strong> related to a form submission.
- * Validators themselves are stateless singletons.
+ * Used by a {@link Field} to enforce a <strong>constraint</strong> related to a form submission. Validators themselves
+ * are stateless singletons.
  * <p/>
  * Validators are usually encapsulated inside a {@link FieldValidator}.
  *
- * @see org.apache.tapestry.services.FieldValidationSupport
+ * @see FieldValidationSupport
  * @see org.apache.tapestry.services.FieldValidatorDefaultSource
  */
 public interface Validator<C, T>
 {
     /**
-     * Returns the type of constraint value used with this validator. Constraint values are used to
-     * parameterize a validator, for example a "maxLength" validator will have a constraint value of
-     * type int (the maximum length allowed). For constraints that do not have a constraint value,
-     * this method returns null.
+     * Returns the type of constraint value used with this validator. Constraint values are used to parameterize a
+     * validator, for example a "maxLength" validator will have a constraint value of type int (the maximum length
+     * allowed). For constraints that do not have a constraint value, this method returns null.
      */
     Class<C> getConstraintType();
 
     /**
-     * Returns the value type associated with this validator.
-     * {@link #validate(Field, Object, MessageFormatter, Object)} will only be invoked when the
-     * value is assignable to the validator's value type.
+     * Returns the value type associated with this validator. {@link #validate(Field, Object, MessageFormatter, Object)}
+     * will only be invoked when the value is assignable to the validator's value type.
      */
     Class<T> getValueType();
 
     /**
-     * Returns the message key, within the validiation messages, normally used by this validator.
-     * This is used to provide the {@link MessageFormatter} passed to
-     * {@link #validate(Field, Object, MessageFormatter, Object)} (unless overridden).
+     * Returns the message key, within the validiation messages, normally used by this validator. This is used to
+     * provide the {@link MessageFormatter} passed to {@link #validate(Field, Object, MessageFormatter, Object)} (unless
+     * overridden).
      *
      * @return a message key
      * @see ValidationMessagesSource
@@ -55,9 +53,9 @@
     String getMessageKey();
 
     /**
-     * Invoked after the client-submitted value has been {@link Translator translated} to check that
-     * the value conforms to expectations (often, in terms of minimum or maximum value). If and only
-     * if the value is approved by all Validators is the value applied by the field.
+     * Invoked after the client-submitted value has been {@link Translator translated} to check that the value conforms
+     * to expectations (often, in terms of minimum or maximum value). If and only if the value is approved by all
+     * Validators is the value applied by the field.
      *
      * @param field           the field for which a client submitted value is being validated
      * @param constraintValue the value used to constrain
@@ -68,20 +66,19 @@
     void validate(Field field, C constraintValue, MessageFormatter formatter, T value) throws ValidationException;
 
     /**
-     * Returns true if the validator should be invoked for null or blank (empty string) values. This
-     * is generally false.
+     * Returns true if the validator should be invoked for null or blank (empty string) values. This is generally
+     * false.
      */
     boolean invokeIfBlank();
 
     /**
-     * Hook used by components to allow the validator to contribute additional attribute or (more
-     * often) client-side JavaScript (via the {@link PageRenderSupport}).
+     * Hook used by components to allow the validator to contribute additional attribute or (more often) client-side
+     * JavaScript (via the {@link PageRenderSupport}).
      *
      * @param field           the field which is currently being rendered
      * @param constraintValue the value used to constrain input
      * @param formatter       validation message, in the appropriate locale
-     * @param writer          markup writer, allowing additional attributes to be written into the active
-     *                        element
+     * @param writer          markup writer, allowing additional attributes to be written into the active element
      * @param formSupport
      */
     void render(Field field, C constraintValue, MessageFormatter formatter, MarkupWriter writer,

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java Thu Jan 17 16:52:51 2008
@@ -18,7 +18,7 @@
 import org.apache.tapestry.annotations.*;
 import org.apache.tapestry.corelib.mixins.RenderDisabled;
 import org.apache.tapestry.ioc.annotations.Inject;
-import org.apache.tapestry.services.FieldValidationSupport;
+import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.services.FieldValidatorDefaultSource;
 import org.apache.tapestry.services.Request;
 import org.apache.tapestry.services.TranslatorDefaultSource;
@@ -35,7 +35,7 @@
  * <p/>
  * If the component container (i.e., the page) provides an event handler method for the "toclient" event, and that
  * handler returns a non-null string, that will be the string value sent to the client. The context passed to the event
- * handler method is the current value of the value parameter.
+ * handler method is t he current value of the value parameter.
  * <p/>
  * Likewise, on a form submit, the "parseclient" event handler method will be passed the string provided by the client,
  * and may provide a non-null value as the parsed value.  Returning null allows the normal translator to operate.  The
@@ -67,6 +67,14 @@
     @SuppressWarnings("unchecked")
     private FieldValidator<Object> _validate = NOOP_VALIDATOR;
 
+    /**
+     * Defines how nulls on the server side, or sent from the client side, are treated. The selected strategy may
+     * replace the nulls with some other value. The default strategy leaves nulls alone.  Another built-in strategy,
+     * zero, replaces nulls with the value 0.
+     */
+    @Parameter(defaultPrefix = "nullfieldstrategy", value = "default")
+    private NullFieldStrategy _nulls;
+
     @Environmental
     private ValidationTracker _tracker;
 
@@ -136,7 +144,25 @@
     {
         String value = _tracker.getInput(this);
 
-        if (value == null) value = _fieldValidationSupport.toClient(_value, _resources, _translate);
+        // If this is a response to a form submission, and the user provided a value.
+        // then send that exact value back at them.
+
+        if (value == null)
+        {
+            // Otherwise, get the value from the parameter ...
+
+            Object untranslated = _value;
+
+            // Substitute an alternative for null values.
+            // TODO: May want to coerce untranslated to the bound parameter type, to ensure it is compatible with the translator.
+
+            if (untranslated == null) untranslated = _nulls.replaceToClient();
+
+            // Then let the translator and or various triggered events get it into
+            // a format ready to be sent to the client.
+
+            value = _fieldValidationSupport.toClient(untranslated, _resources, _translate);
+        }
 
         writeFieldTag(writer, value);
 
@@ -170,6 +196,8 @@
 
         try
         {
+            if (InternalUtils.isBlank(rawValue)) rawValue = _nulls.replaceFromClient();
+
             Object translated = _fieldValidationSupport.parseClient(rawValue, _resources, _translate);
 
             _fieldValidationSupport.validate(translated, _resources, _validate);

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultNullFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultNullFieldStrategy.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultNullFieldStrategy.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultNullFieldStrategy.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,39 @@
+// Copyright  2008 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.tapestry.internal;
+
+import org.apache.tapestry.NullFieldStrategy;
+
+/**
+ * Default strategy, which is to do nothing: null values stay null.
+ */
+public class DefaultNullFieldStrategy implements NullFieldStrategy
+{
+    /**
+     * Returns null.
+     */
+    public Object replaceToClient()
+    {
+        return null;
+    }
+
+    /**
+     * Returns the empty string.
+     */
+    public String replaceFromClient()
+    {
+        return "";
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/ZeroNullFieldStrategy.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/ZeroNullFieldStrategy.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/ZeroNullFieldStrategy.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/ZeroNullFieldStrategy.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,39 @@
+// Copyright  2008 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.tapestry.internal;
+
+import org.apache.tapestry.NullFieldStrategy;
+
+/**
+ * Treats nulls to or from the client as if they were 0's.
+ */
+public class ZeroNullFieldStrategy implements NullFieldStrategy
+{
+    /**
+     * Returns the value 0.
+     */
+    public Object replaceToClient()
+    {
+        return 0l;
+    }
+
+    /**
+     * Returns "0".
+     */
+    public String replaceFromClient()
+    {
+        return "0";
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/NullFieldStrategyBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/NullFieldStrategyBindingFactory.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/NullFieldStrategyBindingFactory.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/NullFieldStrategyBindingFactory.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,44 @@
+// Copyright  2008 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.tapestry.internal.bindings;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.NullFieldStrategy;
+import org.apache.tapestry.ioc.Location;
+import org.apache.tapestry.services.BindingFactory;
+import org.apache.tapestry.services.NullFieldStrategySource;
+
+/**
+ * Treats the expression as the name of a {@link org.apache.tapestry.NullFieldStrategy}, accessed via the {@link
+ * org.apache.tapestry.services.NullFieldStrategySource} service.
+ */
+public class NullFieldStrategyBindingFactory implements BindingFactory
+{
+    private NullFieldStrategySource _strategySource;
+
+    public NullFieldStrategyBindingFactory(NullFieldStrategySource strategySource)
+    {
+        _strategySource = strategySource;
+    }
+
+    public Binding newBinding(String description, ComponentResources container, ComponentResources component,
+                              String expression, Location location)
+    {
+        NullFieldStrategy strategy = _strategySource.get(expression);
+
+        return new LiteralBinding(description, strategy, location);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/FieldValidationSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/FieldValidationSupportImpl.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/FieldValidationSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/FieldValidationSupportImpl.java Thu Jan 17 16:52:51 2008
@@ -21,7 +21,6 @@
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.runtime.ComponentEventException;
-import org.apache.tapestry.services.FieldValidationSupport;
 import org.apache.tapestry.services.ValidationMessagesSource;
 
 public class FieldValidationSupportImpl implements FieldValidationSupport

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImpl.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImpl.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,40 @@
+// Copyright  2008 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.tapestry.internal.services;
+
+import org.apache.tapestry.NullFieldStrategy;
+import org.apache.tapestry.services.NullFieldStrategySource;
+
+import java.util.Map;
+
+public class NullFieldStrategySourceImpl implements NullFieldStrategySource
+{
+    private final Map<String, NullFieldStrategy> _configuration;
+
+    public NullFieldStrategySourceImpl(Map<String, NullFieldStrategy> configuration)
+    {
+        _configuration = configuration;
+    }
+
+    public NullFieldStrategy get(String name)
+    {
+        NullFieldStrategy result = _configuration.get(name);
+
+        if (result != null) return result;
+
+        throw new IllegalArgumentException(
+                ServicesMessages.unknownNullFieldStrategyName(name, _configuration.keySet()));
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Thu Jan 17 16:52:51 2008
@@ -395,4 +395,9 @@
     {
         return MESSAGES.format("page-pool-exausted", pageName, locale.toString(), hardLimit);
     }
+
+    static String unknownNullFieldStrategyName(String name, Collection<String> names)
+    {
+        return MESSAGES.format("unknown-null-field-strategy-name", name, InternalUtils.joinSorted(names));
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/NullFieldStrategySource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/NullFieldStrategySource.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/NullFieldStrategySource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/NullFieldStrategySource.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,35 @@
+// Copyright  2008 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.tapestry.services;
+
+import org.apache.tapestry.NullFieldStrategy;
+
+/**
+ * A source for {@link org.apache.tapestry.NullFieldStrategy} instances based on a logical name.
+ *
+ * @see TapestryModule#contributeNullFieldStrategySource(org.apache.tapestry.ioc.MappedConfiguration)
+ */
+public interface NullFieldStrategySource
+{
+    /**
+     * Returns the instance based on the name.  Instances are expected to be stateless and therefore, shareable and
+     * thread safe.
+     *
+     * @param name name of the strategy (case is ignored)
+     * @return the strategy
+     * @throws IllegalArgumentException if the name does not match a configured instance
+     */
+    NullFieldStrategy get(String name);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Thu Jan 17 16:52:51 2008
@@ -19,9 +19,7 @@
 import org.apache.tapestry.beaneditor.Validate;
 import org.apache.tapestry.corelib.data.GridPagerPosition;
 import org.apache.tapestry.grid.GridDataSource;
-import org.apache.tapestry.internal.DefaultValidationDecorator;
-import org.apache.tapestry.internal.InternalConstants;
-import org.apache.tapestry.internal.TapestryInternalUtils;
+import org.apache.tapestry.internal.*;
 import org.apache.tapestry.internal.beaneditor.PrimitiveFieldConstraintGenerator;
 import org.apache.tapestry.internal.beaneditor.ValidateAnnotationConstraintGenerator;
 import org.apache.tapestry.internal.bindings.*;
@@ -112,6 +110,7 @@
         binder.bind(PageContentTypeAnalyzer.class, PageContentTypeAnalyzerImpl.class);
         binder.bind(ResponseRenderer.class, ResponseRendererImpl.class);
         binder.bind(RequestPathOptimizer.class, RequestPathOptimizerImpl.class);
+        binder.bind(NullFieldStrategySource.class, NullFieldStrategySourceImpl.class);
     }
 
     public static Alias build(Logger logger,
@@ -139,8 +138,8 @@
     }
 
     /**
-     * Contributes the factory for serveral built-in binding prefixes ("asset", "literal", prop", "block", "component"
-     * "message", "validate", "translate", "var").
+     * Contributes the factory for serveral built-in binding prefixes ("asset", "block", "component", "literal", prop",
+     * "nullfieldstrategy", "message", "validate", "translate", "var").
      */
     public static void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration,
 
@@ -165,6 +164,7 @@
         configuration.add("block", new BlockBindingFactory());
         configuration.add("asset", locator.autobuild(AssetBindingFactory.class));
         configuration.add("var", new RenderVariableBindingFactory());
+        configuration.add("nullfieldstrategy", locator.autobuild(NullFieldStrategyBindingFactory.class));
     }
 
     public static void contributeClasspathAssetAliasManager(MappedConfiguration<String, String> configuration,
@@ -2056,5 +2056,17 @@
         if (immediateMode) return locator.autobuild(ImmediateActionRenderResponseGenerator.class);
 
         return locator.autobuild(ActionRenderResponseGeneratorImpl.class);
+    }
+
+    /**
+     * Contributes strategies accessible via the {@link NullFieldStrategySource} service.
+     * <p/>
+     * <dl> <dt>default</dt> <dd>Does nothing, nulls stay null.</dd> <dt>zero</dt> <dd>Null values are converted to
+     * zero.</dd> </dl>
+     */
+    public static void contributeNullFieldStrategySource(MappedConfiguration<String, NullFieldStrategy> configuration)
+    {
+        configuration.add("default", new DefaultNullFieldStrategy());
+        configuration.add("zero", new ZeroNullFieldStrategy());
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Thu Jan 17 16:52:51 2008
@@ -89,4 +89,5 @@
 invalid-block-id=Block id '%s' is not valid; block ids must be valid Java identifiers: start with a letter, and consist of letters, numbers and underscores. 
 page-pool-exausted=The page pool for page '%s' (in locale %s) has been exausted: there are %d instances currently being used and no more can be created. \
   Try increasing the hard limit (symbol tapestry.page-pool.hard-limit) to allow additional instances to be created, \
-  or increasing the soft wait (symbol tapestry.page-pool.soft-wait) to trade away some throughput for more efficient use of page instances.
\ No newline at end of file
+  or increasing the soft wait (symbol tapestry.page-pool.soft-wait) to trade away some throughput for more efficient use of page instances.
+unknown-null-field-strategy-name=Unrecognized name '%s' locating a null field strategy.  Available strategies: %s.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt Thu Jan 17 16:52:51 2008
@@ -123,6 +123,8 @@
 *------------+----------------------------------------------------------------------------------+
 | literal    | A literal string.                                                                |
 *------------+----------------------------------------------------------------------------------+
+| nullfieldstrategy | Used to locate a pre-defined {{{../../apidocs/org/apache/tapestry/NullFieldStrategy.html}NullFieldStrategy}}|
+*------------+----------------------------------------------------------------------------------+
 | message    | Retrieves a value from the component's {{{localization.html}message catalog}}.   |
 *------------+----------------------------------------------------------------------------------+
 | prop       | The name of a property of the containing component to read or update.            |

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml Thu Jan 17 16:52:51 2008
@@ -0,0 +1,23 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+    <h1>Null Field Strategy Demo</h1>
+
+    <p>
+        Demonstrates the use of the nulls parameter of TextField to change how null values are treated.
+    </p>
+
+
+    <t:form>
+        <t:textfield t:id="number" nulls="zero"/>
+        <br/>
+        <input type="submit" value="Update"/>
+    </t:form>
+
+    <hr/>
+
+    <p>
+        Number property value:
+        <span id="value">${number}</span>
+    </p>
+
+</html>
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Thu Jan 17 16:52:51 2008
@@ -1414,4 +1414,25 @@
 
         assertText(locator, "100");
     }
+
+    /**
+     * TAPESTRY-2056
+     */
+    @Test
+    public void null_field_strategy()
+    {
+        start("Null Field Strategy Demo");
+
+        String locator = "//span[@id='value']";
+
+        assertText(locator, "");
+
+        assertText("//input[@id='number']/@value", "0");
+
+        type("number", "");
+
+        clickAndWait(SUBMIT);
+
+        assertText(locator, "0");
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/NullStrategyDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/NullStrategyDemo.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/NullStrategyDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/NullStrategyDemo.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,33 @@
+// Copyright  2008 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.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.Persist;
+
+public class NullStrategyDemo
+{
+    @Persist
+    private Long _number;
+
+    public Long getNumber()
+    {
+        return _number;
+    }
+
+    public void setNumber(Long number)
+    {
+        _number = number;
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/Start.java Thu Jan 17 16:52:51 2008
@@ -199,7 +199,9 @@
             new Item("unlessdemo", "Unless Demo", "use of the Unless component"),
 
             new Item("MagicValueEncoder", "Magic ValueEncoder Demo",
-                     "Automatic creation of ValueEncoder using the TypeCoercer"));
+                     "Automatic creation of ValueEncoder using the TypeCoercer"),
+
+            new Item("NullStrategyDemo", "Null Field Strategy Demo", "use of the nulls parameter of TextField"));
 
     static
     {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/FieldValidationSupportImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/FieldValidationSupportImplTest.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/FieldValidationSupportImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/FieldValidationSupportImplTest.java Thu Jan 17 16:52:51 2008
@@ -18,7 +18,6 @@
 import org.apache.tapestry.corelib.internal.InternalMessages;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.runtime.ComponentEventException;
-import org.apache.tapestry.services.FieldValidationSupport;
 import org.apache.tapestry.services.ValidationMessagesSource;
 import org.apache.tapestry.test.TapestryTestCase;
 import org.easymock.EasyMock;

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImplTest.java?rev=613029&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/NullFieldStrategySourceImplTest.java Thu Jan 17 16:52:51 2008
@@ -0,0 +1,59 @@
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.NullFieldStrategy;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry.services.NullFieldStrategySource;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class NullFieldStrategySourceImplTest extends InternalBaseTestCase
+{
+    @Test
+    public void success()
+    {
+        NullFieldStrategy strategy = mockNullFieldStrategy();
+
+        replay();
+
+        Map<String, NullFieldStrategy> configuration = Collections.singletonMap("strat", strategy);
+
+        NullFieldStrategySource source = new NullFieldStrategySourceImpl(configuration);
+
+        assertSame(source.get("strat"), strategy);
+
+        verify();
+    }
+
+    @Test
+    public void failure()
+    {
+        Map<String, NullFieldStrategy> configuration = CollectionFactory.newCaseInsensitiveMap();
+
+        configuration.put("fred", mockNullFieldStrategy());
+        configuration.put("barney", mockNullFieldStrategy());
+
+        replay();
+
+        NullFieldStrategySource source = new NullFieldStrategySourceImpl(configuration);
+
+        try
+        {
+            source.get("wilma");
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(ex.getMessage(),
+                         "Unrecognized name 'wilma' locating a null field strategy.  Available strategies: barney, fred.");
+        }
+
+    }
+
+    protected final NullFieldStrategy mockNullFieldStrategy()
+    {
+        return newMock(NullFieldStrategy.class);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/services/TapestryIOCModule.java Thu Jan 17 16:52:51 2008
@@ -56,10 +56,9 @@
     }
 
     /**
-     * Provides access to additional service lifecycles. One lifecycles is built in ("singleton")
-     * but additional ones are accessed via this service (and its mapped configuration). Only
-     * proxiable services (those with explicit service interfaces) can be managed in terms of a
-     * lifecycle.
+     * Provides access to additional service lifecycles. One lifecycles is built in ("singleton") but additional ones
+     * are accessed via this service (and its mapped configuration). Only proxiable services (those with explicit
+     * service interfaces) can be managed in terms of a lifecycle.
      */
     public static ServiceLifecycleSource build(final Map<String, ServiceLifecycle> configuration)
     {
@@ -82,11 +81,9 @@
     }
 
     /**
-     * Contributes "DefaultProvider", ordered last, that delegates to
-     * {@link ObjectLocator#getService(Class)}.
+     * Contributes "DefaultProvider", ordered last, that delegates to {@link ObjectLocator#getService(Class)}.
      * <p/>
-     * Contributes "Value", which injects values (not services) triggered by the {@link Value}
-     * annotation.
+     * Contributes "Value", which injects values (not services) triggered by the {@link Value} annotation.
      */
     public static void contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> configuration,
 
@@ -97,46 +94,22 @@
     }
 
     /**
-     * Contributes a set of standard type coercions to the {@link TypeCoercer} service:
-     * <ul>
-     * <li>Object to String</li>
-     * <li>String to Double</li>
-     * <li>String to BigDecimal</li>
-     * <li>BigDecimal to Double</li>
-     * <li>Double to BigDecimal</li>
-     * <li>String to BigInteger</li>
-     * <li>BigInteger to Long</li>
-     * <li>String to Long</li>
-     * <li>Long to Byte</li>
-     * <li>Long to Short</li>
-     * <li>Long to Integer</li>
-     * <li>Double to Long</li>
-     * <li>Double to Float</li>
-     * <li>Float to Double</li>
-     * <li>Long to Double</li>
-     * <li>String to Boolean ("false" is always false, other non-blank strings are true)</li>
-     * <li>Long to Boolean (true if long value is non zero)</li>
-     * <li>Null to Boolean (always false)</li>
-     * <li>Null to String (still null)</li>
-     * <li>Collection to Boolean (false if empty)</li>
-     * <li>Object[] to List</li>
-     * <li>primitive[] to List</li>
-     * <li>Object to List (by wrapping as a singleton list)</li>
-     * <li>Null to List (still null)</li>
-     * <li>Null to Long (zero)</li>
-     * <li>Null to BigDecimal (zero)</li>
-     * <li>Null to BigInteger (zero)</li>
-     * <li>String to File</li>
-     * <li>String to {@link org.apache.tapestry.ioc.util.TimeInterval}</li>
-     * <li>{@link org.apache.tapestry.ioc.util.TimeInterval} to Long</li>
-     * </ul>
+     * Contributes a set of standard type coercions to the {@link TypeCoercer} service: <ul> <li>Object to String</li>
+     * <li>String to Double</li> <li>String to BigDecimal</li> <li>BigDecimal to Double</li> <li>Double to
+     * BigDecimal</li> <li>String to BigInteger</li> <li>BigInteger to Long</li> <li>String to Long</li> <li>Long to
+     * Byte</li> <li>Long to Short</li> <li>Long to Integer</li> <li>Double to Long</li> <li>Double to Float</li>
+     * <li>Float to Double</li> <li>Long to Double</li> <li>String to Boolean ("false" is always false, other non-blank
+     * strings are true)</li> <li>Long to Boolean (true if long value is non zero)</li> <li>Null to Boolean (always
+     * false)</li> <li>Null to String (still null)</li> <li>Collection to Boolean (false if empty)</li> <li>Object[] to
+     * List</li> <li>primitive[] to List</li> <li>Object to List (by wrapping as a singleton list)</li> <li>Null to List
+     * (still null)</li> <li>String to File</li> <li>String to {@link org.apache.tapestry.ioc.util.TimeInterval}</li>
+     * <li>{@link org.apache.tapestry.ioc.util.TimeInterval} to Long</li> </ul>
      * <p/>
-     * The coercion of String to Long, BigInteger, Double and BigDecimal causes some minor headaches
-     * when attempting to add coercions from null to various numeric types: we end up having to have
-     * many more coercions for the null case to prevent null --> String --> BigInteger. This may
-     * indicate a weakness in the algorithm, in that coercions through String should be considered
-     * "weaker" than other coercions. Alternately, coercions from null may need to be handled
-     * specially. We'll see if we tweak the algorithm in the future.
+     * The coercion of String to Long, BigInteger, Double and BigDecimal causes some minor headaches when attempting to
+     * add coercions from null to various numeric types: we end up having to have many more coercions for the null case
+     * to prevent null --> String --> BigInteger. This may indicate a weakness in the algorithm, in that coercions
+     * through String should be considered "weaker" than other coercions. Alternately, coercions from null may need to
+     * be handled specially. We'll see if we tweak the algorithm in the future.
      */
     @SuppressWarnings("unchecked")
     public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
@@ -292,38 +265,6 @@
             }
         });
 
-        add(configuration, void.class, Long.class, new Coercion<Void, Long>()
-        {
-            public Long coerce(Void input)
-            {
-                return 0l;
-            }
-        });
-
-        add(configuration, void.class, BigDecimal.class, new Coercion<Void, BigDecimal>()
-        {
-
-            public BigDecimal coerce(Void input)
-            {
-                return BigDecimal.ZERO;
-            }
-        });
-
-        add(configuration, void.class, BigInteger.class, new Coercion<Void, BigInteger>()
-        {
-            public BigInteger coerce(Void input)
-            {
-                return BigInteger.ZERO;
-            }
-        });
-
-        add(configuration, void.class, Double.class, new Coercion<Void, Double>()
-        {
-            public Double coerce(Void input)
-            {
-                return 0d;
-            }
-        });
 
         add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
         {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/coerce.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/coerce.apt?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/coerce.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/coerce.apt Thu Jan 17 16:52:51 2008
@@ -20,9 +20,7 @@
 [images/type-coercer.png] Default Type Coercions  
 
   There's a few special coercions related to null there; Object --\> List wraps a lone object as a singleton list, we then need
-  null --\> List to ensure that null stays null (rather than a singleton list whose lone element is a null).  Likewise, there's
-  a number of coercions from null to numeric types (null is coerced to zero). Several more of these are needed than you'd think, because otherwise
-  the coercer attempts to coerce through String.
+  null --\> List to ensure that null stays null (rather than a singleton list whose lone element is a null). 
   
   Tapestry can <interpolate> necessary coercions.  For example, say it is necessary to coerce a StringBuffer to an Integer; the
   TypeCoercer will chain together a series of coercions:

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/resources/images/type-coercer.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/resources/images/type-coercer.png?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
Binary files - no diff available.

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/services/TypeCoercerImplTest.java Thu Jan 17 16:52:51 2008
@@ -143,43 +143,93 @@
         return new Object[][]{
                 // There's a lot of these!
 
-                {this, String.class, toString()}, {55l, Integer.class, 55}, {"", Boolean.class, false},
-                {"  ", Boolean.class, false}, {"x", Boolean.class, true}, {" z ", Boolean.class, true},
-                {"false", Boolean.class, false}, {"  False ", Boolean.class, false}, {null, Boolean.class, false},
-                {new Double(256), Integer.class, new Integer(256)}, {new Double(22.7), Integer.class, new Integer(22)},
-                {new Integer(0), Boolean.class, false}, {new Long(32838), Boolean.class, true},
-                {new Integer(127), Byte.class, new Byte("127")}, {new Double(58), Short.class, new Short("58")},
-                {new Integer(33), Long.class, new Long(33)}, {new Integer(22), Float.class, new Float(22)},
+                {this, String.class, toString()},
+
+                {55l, Integer.class, 55},
+
+                {"", Boolean.class, false},
+
+                {"  ", Boolean.class, false},
+
+                {"x", Boolean.class, true},
+
+                {" z ", Boolean.class, true},
+
+                {"false", Boolean.class, false},
+
+                {"  False ", Boolean.class, false},
+
+                {null, Boolean.class, false},
+
+                {new Double(256), Integer.class, new Integer(256)},
+
+                {new Double(22.7), Integer.class, new Integer(22)},
+
+                {new Integer(0), Boolean.class, false},
+
+                {new Long(32838), Boolean.class, true},
+
+                {new Integer(127), Byte.class, new Byte("127")},
+
+                {new Double(58), Short.class, new Short("58")},
+
+                {new Integer(33), Long.class, new Long(33)},
+
+                {new Integer(22), Float.class, new Float(22)},
+
                 {new Integer(1234), Double.class, new Double(1234)},
-                {floatValue, Double.class, floatValue.doubleValue()}, {Collections.EMPTY_LIST, Boolean.class, false},
+
+                {floatValue, Double.class, floatValue.doubleValue()},
+
+                {Collections.EMPTY_LIST, Boolean.class, false},
+
                 {Collections.singleton(this), Boolean.class, true},
+
                 {bigDecimalValue, BigDecimal.class, new BigDecimal(bigDecimalValue)},
+
                 {new BigDecimal(bigDecimalValue), Double.class, 1.2345656748352436E49},
+
                 {bigIntegerValue, BigInteger.class, new BigInteger(bigIntegerValue)},
+
                 {new BigInteger("12345678"), Long.class, 12345678l},
+
                 {-12345678l, BigInteger.class, new BigInteger("-12345678")},
-                {object, List.class, Collections.singletonList(object)}, {null, Iterable.class, null},
-                {null, List.class, null}, {null, Collection.class, null}, {null, String.class, null},
+
+                {object, List.class, Collections.singletonList(object)},
+
+                {null, Iterable.class, null},
+
+                {null, List.class, null},
+
+                {null, Collection.class, null},
+
+                {null, String.class, null},
+
                 {new Object[]{"a", 123}, List.class, Arrays.asList("a", 123)},
+
                 {new String[]{"a", "b"}, List.class, Arrays.asList("a", "b")},
+
                 {new byte[]{byte1, byte2}, List.class, Arrays.asList(byte1, byte2)},
+
                 {new short[]{short1, short2}, List.class, Arrays.asList(short1, short2)},
+
                 {new int[]{1, 2}, List.class, Arrays.asList(1, 2)},
+
                 {new long[]{123L, 321L}, List.class, Arrays.asList(123L, 321L)},
+
                 {new float[]{3.4f, 7.777f}, List.class, Arrays.asList(3.4f, 7.777f)},
+
                 {new double[]{3.4, 7.777}, List.class, Arrays.asList(3.4, 7.777)},
+
                 {new char[]{'a', 'b'}, List.class, Arrays.asList('a', 'b')},
+
                 {new boolean[]{true, false}, List.class, Arrays.asList(true, false)},
 
                 {"foo/bar/baz.txt", File.class, new File("foo/bar/baz.txt")},
 
-
                 {new TimeInterval("2 h"), Long.class, 2 * 60 * 60 * 1000l},
-                {"2 h", TimeInterval.class, new TimeInterval("120 m")},
 
-                {null, Long.class, 0l}, {null, Short.class, (short) 0}, {null, Byte.class, (byte) 0},
-                {null, BigDecimal.class, BigDecimal.ZERO}, {null, Float.class, 0f},
-                {null, BigInteger.class, BigInteger.ZERO},
+                {"2 h", TimeInterval.class, new TimeInterval("120 m")},
 
                 // null to arbitrary object is still null
 

Modified: tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java Thu Jan 17 16:52:51 2008
@@ -21,7 +21,6 @@
 import org.apache.tapestry.corelib.base.AbstractField;
 import org.apache.tapestry.corelib.mixins.RenderDisabled;
 import org.apache.tapestry.ioc.annotations.Inject;
-import org.apache.tapestry.services.FieldValidationSupport;
 import org.apache.tapestry.services.FieldValidatorDefaultSource;
 import org.apache.tapestry.services.FormSupport;
 import org.apache.tapestry.upload.services.MultipartDecoder;
@@ -37,15 +36,15 @@
     public static final String MULTIPART_ENCTYPE = "multipart/form-data";
 
     /**
-     * The uploaded file. Note: This is only guaranteed to be valid while processing the form
-     * submission. Subsequently the content may have been cleaned up.
+     * The uploaded file. Note: This is only guaranteed to be valid while processing the form submission. Subsequently
+     * the content may have been cleaned up.
      */
     @Parameter(required = true, principal = true)
     private UploadedFile _value;
 
     /**
-     * The object that will perform input validation. The "validate:" binding prefix is generally
-     * used to provide this object in a declarative fashion.
+     * The object that will perform input validation. The "validate:" binding prefix is generally used to provide this
+     * object in a declarative fashion.
      */
     @Parameter(defaultPrefix = "validate")
     @SuppressWarnings("unchecked")
@@ -77,8 +76,7 @@
     private RenderDisabled _renderDisabled;
 
     /**
-     * Computes a default value for the "validate" parameter using
-     * {@link FieldValidatorDefaultSource}.
+     * Computes a default value for the "validate" parameter using {@link FieldValidatorDefaultSource}.
      */
     final FieldValidator defaultValidate()
     {

Modified: tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry/upload/components/UploadTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry/upload/components/UploadTest.java?rev=613029&r1=613028&r2=613029&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry/upload/components/UploadTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry/upload/components/UploadTest.java Thu Jan 17 16:52:51 2008
@@ -16,7 +16,6 @@
 
 import org.apache.tapestry.*;
 import org.apache.tapestry.dom.Element;
-import org.apache.tapestry.services.FieldValidationSupport;
 import org.apache.tapestry.services.FormSupport;
 import org.apache.tapestry.test.TapestryTestCase;
 import org.apache.tapestry.upload.services.MultipartDecoder;