I'm looking for a very simple form processing API for Java. Assuming the form input fields correspond to bean properties, and all beans have javax.Validation annotations, ideally the API would:
Display a bean as an html form
Populate the bean, including nested objects where applicable, using the request parameters
Validate the input using Validation annotation
If there is an error, display errors at top of form, and highlight error fields.
Additionally:
It would be nice if i didn't have to buy into a whole application framework, since I am working with a legacy app.
Allow configuration for more complicated use cases, but by default just use convention.
Bonus:
generates javascript client side validation too.
Note: If this requires several different libraries, that is fine too.
Update:
Since I never found what I was looking for, and migrating to Spring was not an option, I went ahead and rolled my own solution. It is, affectionately, called java in jails (loosely modeled on rails form processing). It gives you dead simple (and pretty) form creation, client and server side validation, and request parameter to object mapping. No configuration required.
Example Bean:
public class AccountForm {
#NotBlank(groups = RequiredChecks.class)
#Size(min = 2, max = 25)
private String name;
//...
}
Example Form:
<%# taglib uri="http://org.jails.org/form/taglib" prefix="s" %>
<s:form name="accountForm" action="/jails-demo/jails" label="Your Account Details" style="side">
<s:text name="name" label="Name" size="25" />
<s:text name="accountName" label="Account Name" size="15" />
...
</s:form>
Example Validation and Mapping:
SimpleValidator validator = new SimpleValidator();
if ("submit".equals(request.getParameter("submit"))) {
Map<String, List<String>> errors = validator.validate(AccountForm.class, request.getParameterMap());
if (errors != null) {
AccountForm account = validator.getMapper().toObject(AccountForm.class, request.getParameterMap());
//do something with valid account
} else {
SimpleForm.validateAs(AccountForm.class).inRequest(request).setErrors(errors);
//handle error
}
} else {
SimpleForm.validateAs(AccountForm.class).inRequest(request);
//forward to formPage
}
This is what the form looks like, with client side validation using jQuery (provided by Position Absolute):
I don't think you will find something that has most of this functionality and is not a framework.
I can recommend Spring MVC - you can plug it in easily in the legacy app. It supports all of the above.
Doing-it-yourself won't be that hard either:
use BeanUtils.populate(bean, request.getParameterMap()) to fill your object with the request parameters
use javax.validation.* manually - here is how. For each error add request attributes which you can later display as errors.
Note that either way you will have to write the html code manually.
Related
I am trying to validate 2 model attributes on one action using spring validation framework. The purpose is to validate the lookUpbean (search criterion) on click of Search button and then to validate the resultant bean also i.e memberShipbean once we get it from the services so that we can show warnings to the user if some fields are empty in the resultant bean.
<form:form method="POST" modelAttribute="lookupPageBean" id="lookupForm" name="lookupForm"
action="lookupMembership.htm">
<td class="error">
<form:errors path="membershipNumber" />
<form:input class="medium-textbox" id="membershipNumber" path="membershipNumber" />
<button type="submit" class="Active-button-small">
<fmt:message key="button.go" />
</button>`
#RequestMapping(method = RequestMethod.POST, value = URLMappingConstant.MEMBERSHIP_LOOKUP)
public String viewMembership(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response,
#ModelAttribute(UIConstant.LOOKUP_PAGE_BEAN) LookupPageBean lookupPageBean, BindingResult result,
#ModelAttribute(UIConstant.MEMBERSHIP_BEAN) MembershipPageBean membershipPageBean, BindingResult error) throws WebMTracksException
{
membershipValidator.validate(lookupPageBean, result);
membershipValidator.validate(membershipPageBean, error);
}
Now what is happening is first validation is working fine however during second validation
the error messages are not shown on the resultant jsp ,
however the errors are reported till this controller layer in the “error” binding results.
Also in the validation layer
ValidationUtils.rejectIfEmpty(errors, UIConstant.BUSINESSNAME,ValidationMSGConstants.BUSINESS_NAME)
This method always returns validation errors even if the field is not empty.
First question is can we have multiple model attributes in one action. I read it somewhere on internet but could not find any implementation of the same. Please help me to resolve this issue. Also let me know if you can think of any other working solution for this problem but I would like to use only the spring framework for the both the validations as that helps to maintain the existing design of the application.
I do not think you have bind multiple Model Attributes to the same form, which I believe is what you are asking. I am not even sure what that request would look like, from an HTTP stand point, as I don't believe Spring would have a way to detangle all the bean's properties, especially if the names overlap. What you may want to consider doing is wrapping your LookupPageBean and MembershipPageBean into one "form bean".
As for the error messages, you may want to take a look at the spring:bind tag. It may do what you are needed to get the binding errors from the second Model Attribute.
I'm implementing a JSP which expects a few parameters which have to be validated before running the jsp.
Suggestion: Validate the parameters inside the JSP using
Taglibraries
Suggestion: Pre-parse the Parameters in a Filter
What do you think?
Edit
Thank you for the good answers, but I was wondering what would be the best practice in case you are offering a service like google chart API where you can't expect that the parameters are checked by a form before they are sent.
example:
https://chart.googleapis.com/chart?cht=&chd=&chs=&...additional_parameters...
None of both are good approaches. Controller/business logic doesn't belong in a JSP (tag). A filter is almost good, but it's not specific enough. This job should be done by a servlet. You're submitting the form to a servlet to postprocess it, right? It sounds like that you're not already doing that, the answer would otherwise have been pretty straightforward.
In our servlets tag wiki page you can find a hello world example of a good approach of using a JSP with a Servlet to postprocess a form submit. Here's an extract of relevance:
<input id="name" name="name" value="${fn:escapeXml(param.name)}">
<span class="error">${messages.name}</span>
with
String name = request.getParameter("name");
if (name == null || name.trim().isEmpty()) {
messages.put("name", "Please enter name");
}
// ...
request.getRequestDispatcher("/WEB-INF/hello.jsp").forward(request, response);
Further, there exist MVC frameworks which removes all the boilerplate (duplicated/repeated) servlet code for this kind of use cases, such as JSF, Spring MVC, Wicket, Stripes, Struts2, etc. With for example JSF it look just something like this:
<h:inputText id="name" value="#{bean.name}" required="true" requiredMessage="Please enter name" />
<h:message for="name" />
That's all. The JSF's FacesServlet controller servlet will validate if it's been filled in and display a (configureable) message at the given location, without any need for custom Java code. You could even move it to the model, JSF has transparent support for JSR303 bean validation as well. E.g.
<h:inputText id="name" value="#{bean.name}" />
<h:message for="name" />
with
#NotNull(message="Please enter name")
private String name;
Update as per your edit:
Thank you for the good answers, but I was wondering what would be the best practice in case you are offering a service like google chart API where you can't expect that the parameters are checked by a form before they are sent. example: https://chart.googleapis.com/chart?cht=&chd=&chs=&...additional_parameters...
Just use a servlet the same way. The only difference is that you've to implement the job in doGet() instead of doPost() and if necessary return HTTP 400 on an error :) Once again, check our servlets tag wiki page to understand their purpose better. Or to go a step further, use a webservice framework instead, such as JAX-WS or JAX-RS which do this job transparently like a MVC framework does for HTML pages.
Use an MVC Framework (Spring MVC, Stripes, Struts 2 etc.) and validate the parameters in the controller class. Every MVC framework supports parameter validation, and you get a clean separation of concerns.
Example: Spring MVC automatically registers JSR-303-style parameter Validation (if you have a JSR-303 provider, e.g. Hibernate-Validator, on the classpath) when using mvc:annotation-driven
I'm trying to understand the concept of data binding in Spring-MVC with Velocity (I'm learning this framework and porting an app to this platform).
I'm used to getting form variables using request.getParameter("username"), in the Spring world it seems that I can perform validation and such against "form objects" e.g. a datamodel style object that represent all the fields of a form.
The concept of a validator makes sense, but marshaling the data from a query string to these objects is fuzzy for me still. This is the concept of "Data Binding" correct?
If I'm correct to this point a few specific questions:
When a "binding" is made between a form variable (say "username" for example) and the the field of an object (say org.a.b.MyNewUserFormObj.username) is that "binding" a permanent definition such that all subsequent http posts of that form cause the username form variable to be assigned to org.a.b.MyNewUserFormObj.username?
How in the world do I accomplish the above binding definition? (if what I've said up to now is correct I feel like Costello in 'Who's on First', I don't even know what I just said!), I just need a conceptual picture.
Thanks for setting straight a brain gone astray.
There is no magic in data binding.
Actually, Spring simply populate properties of #ModelAttribute object with the values of request parameters with the corresponding names (in the simpliest case request parameter have the same name as a property, but nested properties are also supported).
So, if you have
<input type = "text" name = "firstName" />
and
public class Person {
private String firstName;
... getters, setters ...
}
you get a value from the form field.
Spring also provides convenient method for creating HTML forms. So, instead of creating form fields manually, you can write in JSP:
<form:form modelAttribute = "person" ...>
<form:input path = "firstName" />
</form:form>
or in Velocity (note that in this case <form> is created manually and property path is prefixed with the model attribute name):
<form ...>
#springFormInput("person.firstName" "")
</form>
Fields of the forms generated this way will be prepopulated with the values of the corresponding properties of the model attribute (that's why model attribute name is needed).
is there a way to use groovy builders to build JSP files in a Grails application keeping things enough integrated?
To explain better: by default Grails uses gsp files that are nice but quite verbose..
<div class="clear">
<ul id="nav">
<li><g:link controller="snippets" action="list">Snippets</g:link></li>
<li><g:link controller="users" action="list">Users</g:link></li>
<li><g:link controller="problems" action="list">Problems</g:link></li>
<li><g:link controller="messages" action="list">Messages</g:link></li>
</div>
<div id="content">
is there a way to use groovy.xml.MarkupBuilder tha would turn the previous piece into
div(class:'clear') {
ul(id:'nav') {
li { g_link(controller:'snippets', action:'list', 'Snippets') }
// and so on
Of course g_link is invented just to give the idea..
Do a search for builder under the web layer section of the grails user guide. There is an example in there that shows you exactly how to do this using the xml builder.
I don't have a complete answer for you, but I suspect the key will be gaining access to the "view resolvers". In a normal SpringMVC app, these are configured in views.properties (or views.xml) as follows:
csv=com.example.MyCSVResolver
xml=com.example.MyXMLResolver
audio=com.example.MySpeechResolver
In a regular SpringMVC app, you return something like new ModelAndView(myModel, 'csv') from a controller action.
This would cause the CSVResolver class to be invoked passing it the data in myModel. In addition to containing the data to be rendered, myModel would likely also contain some formatting options (e.g. column widths).
Spring searches the views file for a key matching the view name. If it doesn't find a match, by default it just renders a JSP with the view name and passes it the model data.
Now back to Grails....remember that Grails is really just a Groovy API over SpringMVC and most of the features of SpringMVC can be accessed from Grails. So if you can figure out how to modify the views file, just change your controller actions to return an appropriate ModelAndView instance, and it should work as described above.
GSP allows you to run arbitrary Groovy code inside <% %> brackets. So you can have something like this (borrowing example from page linked to by BlackTiger):
<% StringWriter w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.html{
head{
title 'Log in'
}
body{
h1 'Hello'
builder.form{ }
}
}
out << w.toString()
%>
Note that the above calls g:form tag, and you can pass additional stuff to it.
So what you are asking for is certainly possible, though I am not sure if it will end up being a win. I'd suggest you perhaps look more at TagLibs in combination with Templates and SiteMesh Layouts - can definitely simplify things tremendously.
I was thinking about the idea of using Ajax instead of TagLib. The most elegant way would be: Using Java Annotation.
The idea is, designers or anybody can make the HTML without any taglib ,just using the "standard" HTML tags with id or name, and call the Javascript. That way any WYSIWYG can be used, developer don't have to care about HTML format or the way it's designed.
In many (at least open-source) WYSIWYG don't show the taglibs in that final result (or have a template of it), so it's hard to "preview". Other reason is, developer should know Java and HTML/TagLibs should not be a must-have, since we got CSS and AJAX.
It should work just like that:
MyClass.java:
import ...
// Use the ResourceBundle resource[.{Locale}].properties
#Jay2JI18n(resourceBundle="org.format.resource",name="MyClassForm")
public class MyClass {
private Integer age;
private String name
private Date dob;
private salary;
#Jay2JLabel(resource="label.name")
#Jay2JMaxLength(value=50,required=true,)
#Jay2JException(resource="exception.message")
public String getName() {
...
}
public void setName(String name) {
if ( name.trim().equal("") ) {
throw new Exception("Name is required");
}
}
/* Getter and setter for age */
...
#Jay2JLabel(message="Salary")
#Jay2JFormat(format="##,###.00",language="en")
#Jay2JFormat(format="##.###,00",language="pt_BR")
// or you could use that to access a property of the ResourceBundle
//#Jay2I18nResource(resource="money.format")
public Date getSalary() {
...
}
/* Setter for salary and getter/setter for the rest */
...
}
Page.html:
<html>
<head>
<SCRIPT>
</SCRIPT>
</head>
<body>
<form onload="Jay2J.formalize(this)">
</form>
</body>
</html>
of it can be a HTML with the fields filled;
PageWithFields.html:
<html>
<head>
<SCRIPT>
</SCRIPT>
</head>
<body>
<form action="myfavoritewaytopostthis" onsubmit="return Jay2J.validate(this)" onload="Jay2J.formalizeExistField(this)">
<label>Name</label><input type="text" name="name" id="name" />
<label>DOB</label><input type="text" name="dateOfBirth" id="dob" />
<label>Salary</label><input type="text" name="salary" id="salary" />
<input type="submit" />
</form>
</body>
</html>
That way the Annotation (no XML, it's like HTML in the way that it's only another file modify and XML is not Java) will define how the HTML will be treated. That way developer can stop developing in HTML and use just JAVA (or JavaScript), do you think that's a valid idea?
When i see your topic title i thought:
You cant use Ajax in stead of a taglib. AJAX is javascript on the client and the taglib is java code on the server.
After reading your post i thought, ah he whats to do what [link text][1] does
But then not entrily the same.
[1]: http://code.google.com/webtoolkit/ GWT
First impression is ... yuck, someone who picks this up will have no idea what they're looking at without learning your (new, different, non-standard) way of doing things. You could do something similar by implementing a tag that takes a bean (value object) and maybe does some minor reflection/annotation inspection to emit the proper html, and you'll save yourself a lot of heartache down the line.
Make your value objects implement a simple interface that your tag will use to extract and format the html, and you can probably get 80-90% of where you're trying to go with 1/2 the work or less.
First impression was, WTF. After reading further, I get a impression that you are trying to address the 'separation of concerns'problem in a different way. Some observations on your approach.
Requires client side scripting to be enabled and hence fails accessibility guide lines.
Reinventing the wheel: Many web frameworks like Tapestry, Wicket try to address these issues and have done a commendable work.
On your comment on binding Java to HTML, the code example doesn't convey the idea very clearly. formalize() seems to create the UI, that implies you have UI (HTML) coded into java (Bad Idea? probably not NakedObjects attempts to you domain models for UI, probably yes if one were to write a page specific code)
validate() is invoked on onSubmit(), Why would I want it to be processed asynchronously!! That aside, using obstrusive java script is way out of fashion (seperation of concerns again)
Your argument on taglibs preventing WYSIWIG, though justifiable, is not entirely valid. Tags cannot be used to compose other tags, each tag is a unique entity that either deals with behaviour or emits some html code. Your argument is valid for the second case. However, if I understand your formalize() correctly, you are doing the same!
Nice to hear some new ideas and Welcome to SO. Also, please use the edit question option until you earn enough reputation to add comments. Adding answers is not the right way!
This idea has some merit, if I understand it correctly.
You could use AOP to modify a servlet that would actually be called for the page. The servlet would then return the html, using the annotations.
This way the programmers don't see the html generation, and if you have a standard javascript library for it, then it may work.
But, just because it works doesn't mean that you should do it.
As was mentioned, there are many frameworks out there that can hide the javascript from programmers, such as JSF, which is basically taglibs and a different navigation scheme.
I remember using the beehive project to do something similar, it was annotation driven so I could basically do everything in java and it generated the javascript, years ago. :)