Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lenient property name casing (beyond standard JavaBeans conventions) [SPR-6491] #11157

Closed
spring-projects-issues opened this issue Dec 1, 2009 · 5 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 1, 2009

Stefan Schmidt opened SPR-6491 and commented

Problems arise when using MVC form-objects are bound through the data binder when the fields use 'unusual' capitalizations:

class Book {
     String Title;
     String ISBN;
     int nInStock;
     public String Book.getTitle() { ... }
     public void   Book.setTitle(String Title) { ...  }

     public String Book.getISBN() { ... }
     public void   Book.setISBN(String ISBN) { ... }

     public int    Book.getNInStock() { ... }
     public void   Book.setNInStock(int nInStock) { ... }
}

Only the following representation of these fields in a MVC form works:

<form:input path="title" />
<form:input path="ISBN" />
<form:input path="NInStock" />

Note, the Title needs to be lowercased whereas ISBN needs to remain uppercase (ie iSBN raises a NotReadablePropertyException). Same for the nInStock field which needs to be uppercased (first letter) and nInStock would raise a NotReadablePropertyException).

This seems to be inconsistent w/r to the conventions used here. Why is title handled different to the other two? Also, why can't we allow a convention where title, iSBN and nInStock all work assuming that the get methods follow JavaBean conventions with correct accessors and mutators as shown above? The data binder would just uppercase the first letter of the form field and prepend get and set accordingly.

Maybe I am missing a pattern here but this seems to be handled very inconsistently.


Affects: 3.0 RC3

Issue Links:

Referenced from: commits 388edd7

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

This is unfortunately exactly what the JavaBeans conventions say. See java.beans.Introspector.decapitalize and its javadoc:

[quote]This normally means converting the first character from upper case to lower case, but in the (unusual) special case when there is more than one character and both the first and second characters are upper case, we leave it alone. Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays as "URL".[/quote]

We are simply calling the standard JavaBeans Introspector which detects properties that way. We can of course consider being more lenient here through custom fallback code after the Introspector did its job.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Stefan Schmidt commented

Hi Juergen,

I have done some more tests and there is still a case in the script above that does produce the NotReadablePropertyException. The Introspector.decapitalize() method handles the fields as follows:

Introspector.decapitalize("Title"); // prints title
Introspector.decapitalize("ISBN"); // prints ISBN
Introspector.decapitalize("nInStock"); // prints nInStock

However, defining a form field for the nInStock field like so:

<form:input path="nInStock" />

.. fails with:

org.springframework.beans.NotReadablePropertyException: Invalid property 'nInStock' of bean class [com.springsource.demo.library.domain.Book]: Bean property 'nInStock' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:655)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:647)
at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:96)
at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:224)
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:175)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:195)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:161)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:124)
at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:409)
at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:140)
at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:91)
at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:78)
at org.apache.jsp.WEB_002dINF.views.book.create_jspx._jspx_meth_form_005finput_005f2(create_jspx.java:718)
at org.apache.jsp.WEB_002dINF.views.book.create_jspx._jspService(create_jspx.java:227)

The nInStock field is capitalized correctly as per the Introspector.decapitalize method, however Spring MVC data binding still fails...

@spring-projects-issues
Copy link
Collaborator Author

Stefan Schmidt commented

So it appears I have to check for the method name and not the field name itself. In that case it would be NInStock when stripping off the get/set and therefore the 'special' case rule applies as described in Introspector.decapitalize()...

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Yes it's always the method name that counts. The JavaBeans Introspector doesn't even look at the fields; it just matches getter and setter methods against each other.

I have actually committed a more lenient lookup mechanism there when I marked this issue as 'resolved'. So Spring 3.0 trunk should already accept any such match, even if the first letter's casing doesn't follow the JavaBeans conventions.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Stefan Schmidt commented

Thanks for making this a little more lenient, I am sure most MVC users are not aware of the exact conventions used here so your adjustment will help them.

In the meantime I have adjusted my code to comply with the Introspector.decapitalize reules against method names instead of field names so I should be completely compliant now ;).

-Stefan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants