You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Matthias Kerkhoff <ma...@BESToffers.de> on 2000/10/23 11:23:09 UTC

Problem with optional form fields

Hi all,

I've noticed a problem with forms containing optional fields.

Suppose you have a form containing some optional fields, that the
user can fill with some value or leave blank. If form validation
fails (for example because the user has not filled in values for
some _other_ mandatory fields) the usual pattern is to redisplay
the form page to the user together with some error messages.

However, due to the way the form-field tags like <struts:text>
are implemented, the optional fields will then contain default
values, if the associated properties are not of type String.


Example:

Imagine a slightly modified subscription.jsp from the struts-example,
that asks the user for an additional (and optional) Integer property.

  <tr>
    <th align="right">
      <struts:message key="prompt.intProperty"/>
    </th>
    <td align="left">
      <struts:text property="intProperty"/>
    </td>
  </tr>

If the user enters invalid values for - let's say - the mail hostname
and leaves the intProperty field blank, the subscription.jsp will be
redisplayed. This time, the intProperty field will contain a 0 (instead
of being empty). Depending on the semantic behind intProperty this could
make a serious difference, when this form is resubmitted.

Is this behaviour intended ?

-- 
Matthias                          mailto:make@BESToffers.de



Re: Problem with optional form fields

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Matthias Kerkhoff wrote:

> [snip]
> Am I right, that I could write my own BeanUtils (together with a slightly
> modified ActionServlet) if the majority of struts-users doesn't share my
> opinion ?
>

It is certainly possible for you to do this.

At the moment, BeanUtils doesn't really make overriding particular methods easy,
because it is used as a singleton -- meaning you have to replace the actual
org.apache.struts.util.BeanUtils class itself.  I need to think about possibly
using a factory method of some sort to create a Populator (or something like
that), so that you can register your own implementation without having to modify
anything.

>
> Matthias                        (mailto:make@BESToffers.de)

Craig McClanahan

====================
See you at ApacheCon Europe <http://www.apachecon.com>!
Session VS01 (23-Oct 13h00-17h00):  Sun Technical Briefing
Session T06  (24-Oct 14h00-15h00):  Migrating Apache JServ
                                    Applications to Tomcat





Re[2]: Problem with optional form fields

Posted by Matthias Kerkhoff <ma...@BESToffers.de>.
Hi Craig,

(I sent about an hour ago a message to the list, that seems
 to have been lost somewhere. I've just resend it. In this
 message, I've tried to explain my point of view, which is
 similar to what you've written below. I've added some short
 inline comments - please read my other mail for a more
 detailled reasoning.)
 
>> [...]

> It is a side effect of what is really happening.

> The browser has no real clue that the field is an integer field -- it just
> thinks there is text.  Therefore, what it sends as input for an empty input
> field is a zero-length string, which (unfortunately) the BeanUtils populate
> method treats as a zero when setting an integer field.

Yes, I've tracked it down to populate too. I've seen that all number
conversions methods - ie. convert{Int,Float,Double...) follow the same
pattern...

private static TYPE convertTYPE(String value) {
        try {
            return (new TYPE(value));
        } catch (NumberFormatException e) {
            return (new TYPE(0.0));
        }
    }

I would think, that they should instead do
    
private static TYPE convertTYPE(String value) {
        if (value != null && value.length() > 0) {     // like JSP-spec
                try {
                    return (new TYPE(value));
                } catch (NumberFormatException e) {}
        }
        return null;
    }
}

However, I'm not sure, if such a change would cause undesired side-effects
(I'm especially unsure, what this change means to native number type
 properties like int, double...)

Also, I think the convertBoolean has a similar problem. (Any parameters will
be converted to false, if they're missing, unrecognized or syntactically
incorrect).

> It might make sense to skip calling the setIntProperty() field at all if the
> input is a zero-length string.  JSP follows this rule when you specify
> something like <jsp:setProperty name="beanname" property="*"/>, so this
> would be more consistent with JSP as well.

Yes, that's exactly what I wrote in my previous posting :)

Am I right, that I could write my own BeanUtils (together with a slightly
modified ActionServlet) if the majority of struts-users doesn't share my
opinion ?

Matthias                        (mailto:make@BESToffers.de)



Re[2]: Problem with optional form fields

Posted by Matthias Kerkhoff <ma...@BESToffers.de>.
Hi Pierre,


>> It might make sense to skip calling the setIntProperty() field at all if
> the
>> input is a zero-length string.  JSP follows this rule when you specify
>> something like <jsp:setProperty name="beanname" property="*"/>, so this
>> would be more consistent with JSP as well.
>>
>> What do you think?

> It might create side effects, like with checkboxes where a non checked
> button is not sent to the server.

Checkboxes have to be consired, that's sure. But the exceptional case is the
stupid way, how checkbox-handling is defined for HTML-forms, not the fact,
that the user (and the web-developer) should have the ability to use optional
fields (IMHO).

> Imagine that the user has entered a value in a field, but that field must be
> empty for the form to be validated. When struts redisplays the form with the
> errors, the user empties the field. With your proposal, struts will never
> transmit the empty field to the bean and the validation will always fail...

No, this is not correct. The current codebase should do a formBean.reset()
before populating the bean with the (re-)submitted values. At least, thats
my understanding of ActionServlet.process() and ActionServlet.processPopulate().

> In that particular case, the "" <==> 0 translation creates the whole
> problem. The ActionForm bean should really use String in order to
> distinguish between empty and 0 value. Then, after validation (the
> validation could have to convert the field value in order to check its
> content), the conversion should occur when the definitive values are
> transfered to the business object.

This would be the way to go for simple kinds of validation and low or mid-
performance-range apps. In my case, I would have to pay a performance or
a design-penalty if I do it this way (I think).

Imagine a multipage form, where you want to validate as early as possible
(ie. on the page where the properties have been entered), but also have some
complex inter-relationships between some properties, which are also important
for their validation.

If I understand your suggestion, this would mean
a) that I have to do the String-to-RealType conversion anytime I have to
   check the validity of "dependent" properties or
b) that I have to cache the converted value (to workaround the drawbacks
   of a) in the bean.

I don't like a) because it's sub-optimal in performance terms. b) on the
other side is questionable (for me), because most of my properties are numeric
properties and that would lead to a bean, where I have nearly every
(String-)property shadowed with a numeric property (the cached conversion).

Given the assumption, that there is a way to change the current
implementation without breaking the checkbox-stuff, I'm still
not convinced.

-- 
Matthias                        (mailto:make@BESToffers.de)



Re: Problem with optional form fields

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Pierre Métras wrote:

> Craig McClanahan wrote:
>
> > It might make sense to skip calling the setIntProperty() field at all if
> the
> > input is a zero-length string.  JSP follows this rule when you specify
> > something like <jsp:setProperty name="beanname" property="*"/>, so this
> > would be more consistent with JSP as well.
> >
> > What do you think?
>
> It might create side effects, like with checkboxes where a non checked
> button is not sent to the server.
> Imagine that the user has entered a value in a field, but that field must be
> empty for the form to be validated. When struts redisplays the form with the
> errors, the user empties the field. With your proposal, struts will never
> transmit the empty field to the bean and the validation will always fail...
>

One of the things that is being added to the 1.0 development tree is a reset()
method on ActionForm.  This method is called *before* Struts does the
auto-populate trick.  The contract is that this method should reset all relevant
attributes for this particular form to default values.

For checkboxes, you would want to set the corresponding boolean to false.  It
will be set to true by the auto-populate method *if and only if* the checkbox
was checked (and therefore included in the POST).

For integers, it is technically feasible to distinguish an empty field ("")
versus a zero ("0").  If we decide not to call the setter in this scenario, then
the ActionForm property will remain at it's default value, so you can
distinguish whether it was entered or not.

On the other hand, we could take the approach that the form should have
displayed the default value in the first place, and the user would have had to
erase the existing value to cause an empty string to be posted -- and that the
bean should want to know about that.  Because we have to generate a legal
integer value, the decision is what value to use for indicating "no input".
Zero is the current mechanism for this, but it's not the only choice.


>
> In that particular case, the "" <==> 0 translation creates the whole
> problem. The ActionForm bean should really use String in order to
> distinguish between empty and 0 value. Then, after validation (the
> validation could have to convert the field value in order to check its
> content), the conversion should occur when the definitive values are
> transfered to the business object.
>
> Pierre Métras

Craig McClanahan

====================
See you at ApacheCon Europe <http://www.apachecon.com>!
Session VS01 (23-Oct 13h00-17h00):  Sun Technical Briefing
Session T06  (24-Oct 14h00-15h00):  Migrating Apache JServ
                                    Applications to Tomcat





Re: Problem with optional form fields

Posted by Pierre Métras <ge...@sympatico.ca>.
Craig McClanahan wrote:

> It might make sense to skip calling the setIntProperty() field at all if
the
> input is a zero-length string.  JSP follows this rule when you specify
> something like <jsp:setProperty name="beanname" property="*"/>, so this
> would be more consistent with JSP as well.
>
> What do you think?

It might create side effects, like with checkboxes where a non checked
button is not sent to the server.
Imagine that the user has entered a value in a field, but that field must be
empty for the form to be validated. When struts redisplays the form with the
errors, the user empties the field. With your proposal, struts will never
transmit the empty field to the bean and the validation will always fail...


In that particular case, the "" <==> 0 translation creates the whole
problem. The ActionForm bean should really use String in order to
distinguish between empty and 0 value. Then, after validation (the
validation could have to convert the field value in order to check its
content), the conversion should occur when the definitive values are
transfered to the business object.


Pierre Métras



Re: Problem with optional form fields

Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Matthias Kerkhoff wrote:

> Hi all,
>
> I've noticed a problem with forms containing optional fields.
>
> Suppose you have a form containing some optional fields, that the
> user can fill with some value or leave blank. If form validation
> fails (for example because the user has not filled in values for
> some _other_ mandatory fields) the usual pattern is to redisplay
> the form page to the user together with some error messages.
>
> However, due to the way the form-field tags like <struts:text>
> are implemented, the optional fields will then contain default
> values, if the associated properties are not of type String.
>
> Example:
>
> Imagine a slightly modified subscription.jsp from the struts-example,
> that asks the user for an additional (and optional) Integer property.
>
>   <tr>
>     <th align="right">
>       <struts:message key="prompt.intProperty"/>
>     </th>
>     <td align="left">
>       <struts:text property="intProperty"/>
>     </td>
>   </tr>
>
> If the user enters invalid values for - let's say - the mail hostname
> and leaves the intProperty field blank, the subscription.jsp will be
> redisplayed. This time, the intProperty field will contain a 0 (instead
> of being empty). Depending on the semantic behind intProperty this could
> make a serious difference, when this form is resubmitted.
>
> Is this behaviour intended ?
>

It is a side effect of what is really happening.

The browser has no real clue that the field is an integer field -- it just
thinks there is text.  Therefore, what it sends as input for an empty input
field is a zero-length string, which (unfortunately) the BeanUtils populate
method treats as a zero when setting an integer field.

It might make sense to skip calling the setIntProperty() field at all if the
input is a zero-length string.  JSP follows this rule when you specify
something like <jsp:setProperty name="beanname" property="*"/>, so this
would be more consistent with JSP as well.

What do you think?

> Matthias                          mailto:make@BESToffers.de

Craig McClanahan

====================
See you at ApacheCon Europe <http://www.apachecon.com>!
Session VS01 (23-Oct 13h00-17h00):  Sun Technical Briefing
Session T06  (24-Oct 14h00-15h00):  Migrating Apache JServ
                                    Applications to Tomcat



Re[2]: Problem with optional form fields

Posted by Matthias Kerkhoff <ma...@BESToffers.de>.
> Couldn't you use a variable of type java.lang.Integer instead of an int? That
> way, the default value for the property would be null, and not 0.

That's exactly what I did. Sorry if I missed to make it clear. I used an
Integer in my modified example, that defaults to <null> (ie. non-existant)
in the corresponding SubscriptionForm and Subscription classes.

I suspect that the problem is caused from BeanProperties.convert<Type>,
that converts a null Integer to new Integer(0) behind the scenes. I have
not finally understand when this method get's called (maybe somewhere from
copyProperties?)

-- 
Matthias                        (mailto:make@BESToffers.de)



Re: Problem with optional form fields

Posted by Jean-Baptiste Nizet <je...@s1.com>.

Matthias Kerkhoff wrote:

> Hi all,
>
> I've noticed a problem with forms containing optional fields.
>
> Suppose you have a form containing some optional fields, that the
> user can fill with some value or leave blank. If form validation
> fails (for example because the user has not filled in values for
> some _other_ mandatory fields) the usual pattern is to redisplay
> the form page to the user together with some error messages.
>
> However, due to the way the form-field tags like <struts:text>
> are implemented, the optional fields will then contain default
> values, if the associated properties are not of type String.
>
> Example:
>
> Imagine a slightly modified subscription.jsp from the struts-example,
> that asks the user for an additional (and optional) Integer property.
>
>   <tr>
>     <th align="right">
>       <struts:message key="prompt.intProperty"/>
>     </th>
>     <td align="left">
>       <struts:text property="intProperty"/>
>     </td>
>   </tr>
>
> If the user enters invalid values for - let's say - the mail hostname
> and leaves the intProperty field blank, the subscription.jsp will be
> redisplayed. This time, the intProperty field will contain a 0 (instead
> of being empty). Depending on the semantic behind intProperty this could
> make a serious difference, when this form is resubmitted.
>

Couldn't you use a variable of type java.lang.Integer instead of an int? That
way, the default value for the property would be null, and not 0.

JB.

>
> Is this behaviour intended ?
>
> --
> Matthias                          mailto:make@BESToffers.de

--
Jean-Baptiste Nizet
jean-baptiste.nizet@s1.com

R&D Engineer, S1 Belgium
Kleine Kloosterstraat, 23
B-1932 Sint-Stevens Woluwe
+32 2 200 45 42



Re[2]: Problem with optional form fields

Posted by Matthias Kerkhoff <ma...@BESToffers.de>.
Hi Martin,

> My understanding is that this is how it's supposed to work. The idea behind
> form beans is that they represent exactly what the user entered, so that the
> same information can be used to populate the form when errors occur. A

Yes. In my case, "the same information" would mean to re-populate the optional
field with an empty string.

> struts:text value is, not surprisingly, text, so transforming it to an

I believe struts:text is named 'text' to clarify the relation to the
associated HTML-tag (in this case: <input type=text...>. This pattern
is also used for textarea, submit and so.)

> Integer does not retain all of the information required to do this. For
> example, you cannot distinguish between whether the user entered "0" or "".

Of course "0" and "" are distinguishable. Please note, that my property is
of type "Integer" and not of type int (in which case you're opinion would
be correct).
In my opinion, a non-existing field should _not_ lead to a setXXXProperty-call
(maybe checkboxes are an exception...). You would then get the following
behaviour:

-> User request form page
<- Server sends empty form page
-> User fills form page, makes some errors and leaves optional fields blank
-> User submits form
-> Struts parses the request and converts all (non-empty, non-null) parameters
   to setProperty calls (*)
-> Struts detects an error and forwards to the form.jsp again
-> The form.jsp builds the form page and populates the fields with the
   previously received parameters retrieved from the form bean properties
   (Null properties generate value="", btw.)
<- Server sends re-populated input form again

(*) This behaviour would be consistent with the one the spec. demands
    for <jsp:setProperty param="*">, (ie. to ignore both missing and empty
    parameters).

To come back on the mapping of "0" and ""... I think the correct mapping
should be

FORM   PROPERTY
-----+----------
"0" -> Integer(0)
""  -> null

However, what happens is

FORM   PROPERTY
-----+----------
"0" -> Integer(0)
""  -> Integer(0)

which is not a unique transformation and therefore could not be reversed
when an error is detected and the form has to be repopulated.

> The right way to do this is, I believe, to have all your form bean fields be
> Strings, and do any necessary type conversions as the Action needs to access
> the values in the form bean. The form bean can (and probably should) do the
> validation, though, to ensure that the type conversions will succeed at that
> time.

Maybe I will end up with this, but I still don't think that "it's the right
way" ;)

Matthias                        (mailto:make@BESToffers.de)



Re: Problem with optional form fields

Posted by Jean-Baptiste Nizet <je...@s1.com>.

Martin Cooper wrote:

> My understanding is that this is how it's supposed to work. The idea behind
> form beans is that they represent exactly what the user entered, so that the
> same information can be used to populate the form when errors occur. A
> struts:text value is, not surprisingly, text, so transforming it to an
> Integer does not retain all of the information required to do this. For
> example, you cannot distinguish between whether the user entered "0" or "".
>

I really don't agree with that. To me, a java.lang.Integer object should be kept
to null and not initialized to 0 if the user didn't enter anything. This seems
much more logical to me. BTW, this is how it works in the database/EJB world. If
you read an integer from a database, you get back an object of type
java.lang.Integer, and it's set to null if the int in the database was null.

JB.

>
> The right way to do this is, I believe, to have all your form bean fields be
> Strings, and do any necessary type conversions as the Action needs to access
> the values in the form bean. The form bean can (and probably should) do the
> validation, though, to ensure that the type conversions will succeed at that
> time.
>
> --
> Martin Cooper
> Tumbleweed Communications
>
> ----- Original Message -----
> From: "Matthias Kerkhoff" <ma...@BESToffers.de>
> To: <st...@jakarta.apache.org>
> Sent: Monday, October 23, 2000 2:23 AM
> Subject: Problem with optional form fields
>
> > Hi all,
> >
> > I've noticed a problem with forms containing optional fields.
> >
> > Suppose you have a form containing some optional fields, that the
> > user can fill with some value or leave blank. If form validation
> > fails (for example because the user has not filled in values for
> > some _other_ mandatory fields) the usual pattern is to redisplay
> > the form page to the user together with some error messages.
> >
> > However, due to the way the form-field tags like <struts:text>
> > are implemented, the optional fields will then contain default
> > values, if the associated properties are not of type String.
> >
> >
> > Example:
> >
> > Imagine a slightly modified subscription.jsp from the struts-example,
> > that asks the user for an additional (and optional) Integer property.
> >
> >   <tr>
> >     <th align="right">
> >       <struts:message key="prompt.intProperty"/>
> >     </th>
> >     <td align="left">
> >       <struts:text property="intProperty"/>
> >     </td>
> >   </tr>
> >
> > If the user enters invalid values for - let's say - the mail hostname
> > and leaves the intProperty field blank, the subscription.jsp will be
> > redisplayed. This time, the intProperty field will contain a 0 (instead
> > of being empty). Depending on the semantic behind intProperty this could
> > make a serious difference, when this form is resubmitted.
> >
> > Is this behaviour intended ?
> >
> > --
> > Matthias                          mailto:make@BESToffers.de
> >
> >

--
Jean-Baptiste Nizet
jean-baptiste.nizet@s1.com

R&D Engineer, S1 Belgium
Kleine Kloosterstraat, 23
B-1932 Sint-Stevens Woluwe
+32 2 200 45 42



Re[2]: Problem with optional form fields

Posted by Matthias Kerkhoff <ma...@BESToffers.de>.
Hi Martin,

I've thought more on the subject and think that we (I) have mixed up two
(mostly) unrelated issues.

a) "Reproducing" the original input when an validation error occurs

I'm convinced now, that to reproduce the original input it is necessary
to save the input made as _String_ properties. My (wrong) assumption has
been, that for all kinds of input you have a unique mapping from
String to targetType and backwards. The backward mapping does not exist
in all cases - for example it would be difficult to reconstruct the
exact input string from a floating point number.

> My understanding is that this is how it's supposed to work. The idea behind
> form beans is that they represent exactly what the user entered, so that the
> same information can be used to populate the form when errors occur. A

b) Should Struts show a similar behaviour as specified for
   <jsp:setProperty>

This was my original question and I still think that it would be much
easier to learn Struts, if it would behave the same way as defined
for <jsp:setProperty> in the JSP spec.
The main difference comes from the fact that Struts attempts to convert
empty/missing input to some "meaningful default" value that is then set
as property in the Bean. The JSP spec. however defines that empty request
parameters _must_ be ignored.(*)

In Struts, the bean is unable to distinguish, if the user has left the
field blank or if he itself has entered the "meaningful default" value.

This could lead to various additional problems. One example are optional
form fields.
Here is another example that could not be done with Struts (I think).

Imagine you would change the protocol select control in subscription.jsp
(found in struts-example) to return int's (say 0 for IMAP and 1 for
POP3). The select control should also have an additional entry reading
"Select protocol" that maps to a value of "". In Struts this will not
work as expected. Instead the following behaviour could be observered:

- The user enters some subscription data, but forgets to select the
  mail server protocol. The user then submits the form.
  
- If all other values are validatable, the behind-the-scenes-conversion
  will not be noticed from the form Bean. It will think the user has
  selected IMAP (Because missing integers are converted to Integer(0)).
  --> OUCH!

- If he/she has made some error elsewhere and the form is shown again,
  suddenly the not-specified mail server protocol is set to IMAP (for
  the same reasons as above)
  --> OUCH!

(Of course, this could be solved by associating the default entry
 "Select protocol" with -1 or something like that. I just tried to
 point out a possible problem.)
 
Matthias                        (mailto:make@BESToffers.de)

(*) From pg. 66 JSP1.1:
If the param is not set in the Request object, or if it has the value of ““,
the jsp:setProperty element has no effect (a noop).



Re: Problem with optional form fields

Posted by Martin Cooper <ma...@tumbleweed.com>.
My understanding is that this is how it's supposed to work. The idea behind
form beans is that they represent exactly what the user entered, so that the
same information can be used to populate the form when errors occur. A
struts:text value is, not surprisingly, text, so transforming it to an
Integer does not retain all of the information required to do this. For
example, you cannot distinguish between whether the user entered "0" or "".

The right way to do this is, I believe, to have all your form bean fields be
Strings, and do any necessary type conversions as the Action needs to access
the values in the form bean. The form bean can (and probably should) do the
validation, though, to ensure that the type conversions will succeed at that
time.

--
Martin Cooper
Tumbleweed Communications

----- Original Message -----
From: "Matthias Kerkhoff" <ma...@BESToffers.de>
To: <st...@jakarta.apache.org>
Sent: Monday, October 23, 2000 2:23 AM
Subject: Problem with optional form fields


> Hi all,
>
> I've noticed a problem with forms containing optional fields.
>
> Suppose you have a form containing some optional fields, that the
> user can fill with some value or leave blank. If form validation
> fails (for example because the user has not filled in values for
> some _other_ mandatory fields) the usual pattern is to redisplay
> the form page to the user together with some error messages.
>
> However, due to the way the form-field tags like <struts:text>
> are implemented, the optional fields will then contain default
> values, if the associated properties are not of type String.
>
>
> Example:
>
> Imagine a slightly modified subscription.jsp from the struts-example,
> that asks the user for an additional (and optional) Integer property.
>
>   <tr>
>     <th align="right">
>       <struts:message key="prompt.intProperty"/>
>     </th>
>     <td align="left">
>       <struts:text property="intProperty"/>
>     </td>
>   </tr>
>
> If the user enters invalid values for - let's say - the mail hostname
> and leaves the intProperty field blank, the subscription.jsp will be
> redisplayed. This time, the intProperty field will contain a 0 (instead
> of being empty). Depending on the semantic behind intProperty this could
> make a serious difference, when this form is resubmitted.
>
> Is this behaviour intended ?
>
> --
> Matthias                          mailto:make@BESToffers.de
>
>