Hey, John. I finally got around to looking into this. The behavior you're
seeing is correct, but it's a little bit tricky. ValidationErrors is a map,
where the key is the name of the field and the value is a list of errors
that pertains to the field. In ValidationErrors, the key is the full,
indexed field name (objects[1].integer). It is the fieldName property of the
ValidationError objects that is the stripped field name (objects.integer).
That is intentional. The error's fieldName property is used to construct the
resource lookup key used to find the localized name of the field in your
resource bundle. It would almost always be undesirable -- even impossible
for lists of unknown size -- to have to define a message key for every
element in the list so Stripes allows you to define it once for the list
itself.
The good news is that since the indexed property name is used as the map
key, you can still access the specific error message for a field by using
<s:errors field="objects[1].integer" />. You can then place these near each
input so it is very clear to which input the message applies. For example,
<c:forEach var="i" begin="0" end="5">
<s:input type="text" name="objects[${i}].integer" />
<s:errors field="objects[${i}].integer" />
</c:forEach>
As for the CSS "error" class not getting applied, I'm not seeing that in my
testing. I fired up Bugzooky and test that on the bulk add page and all the
CSS classes were properly applied.
-Ben
On Wed, Aug 6, 2008 at 1:08 PM, Newman, John W <[EMAIL PROTECTED]> wrote:
> Hi,
>
>
>
> I'm not sure if stripes has always worked this way or if something changed
> – and as always I could be doing something wrong. If you have a List<X> in
> an action bean, and one of the fields in the list causes a validation error,
> the field name of the error is list.field, not list[N].field as I would
> expect. This prevents the one field from getting the "error" class. Here's
> a simple example to demonstrate:
>
>
>
> Domain class w/ string & integer
>
> * *
>
> *public* *class* ModelObject {
>
> *private* String string;
>
> *private* Integer integer;
>
>
>
> *public* String getString() {
>
> *return* string;
>
> }
>
> *public* *void* setString(String string) {
>
> *this*.string = string;
>
> }
>
>
>
> *public* Integer getInteger() {
>
> *return* integer;
>
> }
>
> *public* *void* setInteger(Integer integer) {
>
> *this*.integer = integer;
>
> }
>
> }
>
>
>
> Simple Action bean with a list of those
>
>
>
> *public* *class* IndexedValidationErrorAction *extends*
>
> SecureActionBean<User, ActionBeanContext> {
>
>
>
> *private* List<ModelObject> objects;
>
>
>
>
>
> @DefaultHandler
>
> *public* Resolution gotoIndexPage() {
>
> *return* new RedirectResolution("/");
>
> }
>
>
>
>
>
> *public* List<ModelObject> getObjects() {
>
> *return* objects;
>
> }
>
> *public* *void* setObjects(List<ModelObject> objects) {
>
> *this*.objects = objects;
>
> }
>
> }
>
>
>
> *public* *class* TestIndexedValidationErrors *extends*SecureTestFixture<User>{
>
>
>
> @Test
>
> *public* *void* testBody() *throws* Exception {
>
> MockRoundtrip trip =
> createSecureTrip(IndexedValidationErrorAction.*class*);
>
> trip.addParameter("objects[0].string", "asdf");
>
> trip.addParameter("objects[0].integer", "123");
>
> trip.addParameter("objects[1].string", "asdfasdfasdf");
>
> trip.addParameter("objects[1].integer", "xxxx");
>
> trip.addParameter("objects[2].string", "asdasdfadfsasdfasdff"
> );
>
> trip.addParameter("objects[2].integer", "nnn");
>
> trip.execute();
>
> printValidationErrors(trip);
>
> }
>
>
>
> *protected* *void* printValidationErrors(MockRoundtrip trip) {
>
> StringBuffer sb = *new* StringBuffer(255);
>
> sb.append("\n\nValidation Errors:\n");
>
> *for* (Entry<String, List<ValidationError>> e : trip
>
> .getValidationErrors().entrySet()) {
>
> *for* (ValidationError ve : e.getValue()) {
>
> sb.append(ve.getFieldName()).append('\t').append(
>
> ve.getFieldValue()).append('\n');
>
> }
>
> }
>
> sb.append('\n');
>
> LOG.info(sb.toString());
>
> }
>
> }
>
>
>
>
>
> Results in
>
>
>
> Validation Errors:
>
> objects.integer xxxx
>
> objects.integer nnn
>
>
>
> Shouldn't that come back as
>
> objects[1].integer xxxx
>
> objects[2].integer nnn
>
>
>
>
>
> Is that right?
>
> -------------------------------------------------------------------------
> This SF.Net email is sponsored by the Moblin Your Move Developer's
> challenge
> Build the coolest Linux based applications with Moblin SDK & win great
> prizes
> Grand prize is a trip for two to an Open Source event anywhere in the world
> http://moblin-contest.org/redirect.php?banner_id=100&url=/
> _______________________________________________
> Stripes-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/stripes-users
>
>
--
Ben Gunter
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Stripes-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-users