java play 2.0 form not binding - java

Anybody know why my form does not bind
Here is what I have
public class Account {
#Required
private String id = "";
...
}
a form in controlers.Application.java
static Form<Account> accountForm = Form.form(Account.class);
with a method
public static Result addAccount() {
Form<Account> filledForm = accountForm.bindFromRequest();
if (filledForm.hasErrors()) {
...
...
and a scala form template:
#form(action = routes.Application.addAccount()) {
#inputText(accountForm("id"))
<input type="submit" name="action" value="submit ID"/><br />
}
oh and routes line defined as:
GET /createAccount controllers.Application.addAccount()
I printed the data received and it gets the id value and the action submit.
I have printed all validation errors and it seems to be on the id field it just says error.required
don't know cause the address line I am typing in is:
/createAccount?id=1001&action=submit+ID
but the if statement hasErrors() always results to true
Please - is there something obvious I am missing?

When your bean has private fields you need to define proper java bean getters and setters (the binding is done by SpringDataBinder which needs this).

Related

Thymeleaf not recognized my field get method

I have a thymeleaf form and spring boot back-end. I have a model class which has defiened it's getters and setters little bit deferent name. so when Im going to take that model and get its fields as form input fields thymeleaf can not recognised them as fields.
here is my modal,
public class scDto {
private Integer region;
private boolean isAmt;
public scDto() {
}
public Integer getRegion() {
return this.region;
}
public void setRegion(Integer region) {
this.region = region;
}
public boolean isAmt() {
return this.isAmt;
}
public void setAmt(boolean amt) {
this.isAmt = amt;
}
here is my form input field,
<input type="text" th:field="*{sc.isAmt}"/>
here is the error,
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (price:331)
Form is working well for region field. but it does not work for Amt field.
Maybe I can fix this if I changed isAmt() get method to getIsAmt(). But I cant change any method name of the modal class because that class already compiled and I used it via a jar file. Is there anyway to solve this problem.
(Copied from the comments under the question)
I guess you can try to refer to this variable using the {sc.amt}.
More information about the javabeans notation you can read here: stackoverflow.com/a/17066599/7629196
Seeing your DTO it has only 2 fields
public class scDto {
private Integer region;
private boolean isAmt;
public boolean isAmt() {
return this.isAmt;
}
...
}
As per convention
For method name like this
boolean isXyz()
you will read it like xyz
So this line
<input type="text" th:field="*{sc.isAmt}"/>
should be
<input type="text" th:field="*{sc.amt}"/>
Credit also goes to Ruslan K for mentioning this in Comment.
Just adding to add more clarity.

How to bind nested List object to JSP form?

Hello fellow programmers,
I am writing a Spring MVC application for students to do an online assessment with multiple choice questions. An admin should be able to create assessments, so I created this object structure:
#Entity
#Table(name = "assessment")
public class Assessment {
private List<Question> questions;
// getter and setter
}
#Entity
#Table(name = "question")
public class Question {
private String questionText;
private List<Answer> answers;
// getters and setters
}
#Entity
#Table(name = "answer")
public class Answer {
private String answerText;
private boolean isCorrect;
// getters and setters
}
Now, I am using a JSP form on the admin page:
Controller
#RequestMapping(value = "/add/assessment", method = RequestMethod.GET)
public String addAssessments(Model model) {
model.addAttribute("assessmentModel", new Assessment());
return "admin-assessments-create";
}
JSP form
<form:form method="POST" modelAttribute="assessmentModel">
<form:input path="questions[0].questionText" type="text"/> <!-- this is working-->
<form:radiobutton path="questions[0].answers[0].isCorrect"/> <!-- not working-->
<form:input path="questions[0].answers[0].answerText"/>
<button class="btn" type="submit">Submit</button>
</form:form>
When I go to this page I receive the following error:
org.springframework.beans.NotReadablePropertyException:
Invalid property 'questions[0].answers[0].isCorrect' of bean class [com.johndoe.model.Question]:
Bean property 'questions[0].answers[0].isCorrect' is not readable or has an invalid getter method:
Does the return type of the getter match the parameter type of the setter?
I checked all the getters and setters but those are perfectly fine.
Question:
how do I avoid the NotReadablePropertyException and thus bind the nested Answer List to my form?
Use
<form:radiobutton path="questions[0].answers[0].correct"/>
and it will be working.
Why? For boolean fields you have to adapt the get/set paradigm to "is"XYZ(). For the EL expression, you have to drop the "is" in front of the method that accesses the current value of the field, pretty much the same way, you would do with "get" / "set".

Issue with bindFromRequest in Play! Framework 2.3

I'm trying to use the automatic binding feature of Play, without success. I'm developing in Java, on Eclipse 4.4 Luna.
Here is my form :
<h2>Create a new user</h2>
<form action="#routes.Backend.createUser()" method="post">
First Name
<input type="text" name="firstName" />
Last Name
<input type="text" name="lastName" />
E-mail
<input type="email" name="email" />
PIN
<input type="number" name="pin" />
Status
<input type="text" name="status" />
Is guest?
<input type="checkbox" name="isGuest" />
<input type="submit" value="Create user" />
</form>
Here is my class "Users":
#Entity
public class Users extends Model {
// Database columns
#Id
public int userId;
public String firstName;
public String lastName;
public String email;
public int pin;
public String status;
public boolean isGuest;
}
And here is my controller:
public class Backend extends Controller {
public static Result createUser() {
Form<Users> form = Form.form(Users.class).bindFromRequest();
if (form.hasErrors()) {
// doSomething()
} else {
Users u = form.get();
u.save();
}
// TESTING
// Checking the content of the request
DynamicForm requestData = Form.form().bindFromRequest();
String firstName = requestData.get("firstName");
String lastName = requestData.get("lastName");
// Printing the content works, I am able to see the correct values
System.out.println(firstName); // Bob
System.out.println(lastName); // Smith
// This somehow doesn't work...
System.out.println(u.firstName); // NULL
System.out.println(u.lastName); // NULL
System.out.println(u.userId); // Correctly generated
// END OF TESTING
return redirect(routes.Backend.allUsers());
}
}
I wonder why the automatic binding of values doesn't work. I have made sure that the fields name in my form correspond to the attributes names in the class, and this should be enough for the form binding to work, right?
I am using Eclipse Luna, and I turned off automatic project build (I do it manually from the console). I know that sometimes Eclipse can cause issues because of that auto-build feature. Note: This was the way to go, but I didn't clean the project using the activator command, as user Dmitri suggested. Also, you only have to do this once, as long as you don't turn on the automatic build feature in Eclipse.
I have tried restarting Eclipse and the application several times, without success...
EDIT:
I tried using only String attributes for my Users class, since the requestData.get(String s) method returns a String. But still no success...
EDIT 2:
I'm going to bind the values manually... If anyone have an idea, please post :)
EDIT 3:
I've updated my code to follow the rules mentioned in the answer below
EDIT 4:
I can't get autobinding working only when using my Postgresql 9.3 database. When I use in-memory database, everything works smoothly. Also, since there was no JDBC driver for Java 8 and postgresql 9.3, I'm using an older version of the driver (actually the driver is on PGSQL's website, but I couldn't get it working with Play). I will have to check what happens with another DB, then I'll report back here!
EDIT 5:
I tried to create my custom data binder like this:
Formatters.register(User.class, new Formatters.SimpleFormatter<User>() {
#Override
public User parse(String arg0, Locale arg1) throws ParseException {
User u = new Model.Finder<Integer, User>(Integer.class, User.class).byId(Integer.parseInt(arg0));
return u;
}
#Override
public String print(User arg0, Locale arg1) {
return "User : " + arg0.firstName;
}
});
... but it didn't work!
EDIT 6:
User Dmitri has found a working solution: you have to compile the project outside of Eclipse. It seems that there is some incompatibilities between Eclipse's compilator and Play! Framework's compilator...
I have been struggling with exactly the same problem: bindFromRequest returned nulls for "name" field. I did exactly the same what a guy in this Play for Java introduction video did: youtube.com/watch?v=bLrmnjPQsZc . But still no luck.
I've been working on Windows 7 with JDK 1.8. IDE: Eclipse 4.4.0. And I run activator through cygwin.
This is what solved the problem for me:
In Eclipse: Project -> Build Automatically - > turn off
In cygwin:
./activator clean;
./activator compile;
./activator run;
After this, bindFromRequest binds name correctly and puts it into the database.
Create getters/setters for your data model. It has solved my problem.
In your code you have :
Users u = Form.form(Users.class).bindFromRequest().get();
Try with this instead :
Users user = new Users();
Form <Users> u = Form.form(Users.class).fill(user).bindFromRequest();
EDIT :
May be the problem is the input types you're using. Try to generate your form like this :
#form(routes.Backend.createUser()) {
<label>First Name:</label> #inputText(userForm("first_name")) <br />
<label>Last Name:</label> #inputText(userForm("first_name")) <br />
<label>Email:</label> #inputText(userForm("email")) <br />
<label>Pin:</label> #inputText(userForm("pin")) <br />
<label>Status:</label> #inputText(userForm("status")) <br />
<label>Is Guest:</label> #checkbox(userForm("is_guest")) <br />
<input type="submit" value="Create user" />
}
Then in User Entity : try to change all columns type to String
#Entity
public class Users extends Model {
// Database columns
#Id
public int user_id;
public String first_name;
public String last_name;
public String email;
public String pin;
public String status;
public String is_guest;
}
In your controller :
public class Backend extends Controller {
public static Result createUser() {
Form <Users> userForm = Form.form(Users.class).bindFromRequest();
Users user = userForm .get();
user.save();
}
}
There is absolutely no link between the binding and your database. Do not follow #blackbishop's advice telling you to change all the fields of your model to String. That's a very bad idea, if there are different types, there is a reason...
Moreover, Ebean (supposing you're using it) or JPA generate database column types according to your Java properties type. Why would you store a 0 or a 1 in a varchar column ?
Follow these rules :
Use a singular name for your models (User instead of Users)
Always use camel case for your properties, no underscores (firstName instead of first_name, lastName instead of last_name...)
Check errors before getting the value after binding
That should give you this :
public static Result createUser() {
Form<User> form = Form.form(User.class).bindFromRequest();
if (form.hasErrors()) {
// Do what you have to do (i.e. : redirect to the form with a flash message)
}
User u = form.get();
u.save();
return redirect(routes.Backend.allUsers());
}
By the way, in your testing lines, the user_id is correctly generated because you have no validation rules and this data comes from the database, not the form.
I solved this by Adding Setters and Getters.
If you have Entity/Model class you should add setters and getters.
If you have FormData classes add setters and getters for it as well.
So when you call
Form<YourFormData> formData = Form.form(YourFormData.class).bindFromRequest();
YourFormData formData = formData.get();
Your formData will now have all the values set.
Hope this helps!
I know this post has an accepted answer but wanted to post my experience with this issue.
I had the same issue and performed all the steps mentioned in the answer above i.e. Eclipse build automatically and then clean and compile through the activator. However, this did not work. I tried many different ways and even created a project from scratch without creating any Eclipse dependencies. Still, it did not work.
Then, I looked at my model and decided to try by changing the case of my property names, and then voila! It worked!
Here is what my model looked like BEFORE:
public class Test {
public String FirstName;
public String LastName;}
Now, I changed it to look like this:
public class Test {
public String firstName;
public String lastName;}
Just wanted to point this out since it is not obvious and I am coming from .Net

Best Approach to validate a bean

Suppose I have a bean which has lets say 10 properties.
Also I have a error onject which has three propertes viz. errorFlag, errCd, and errMsg
And I want to validate that bean properties sequentialy and I want to break on first occcurence of error and populate the error object.
How can I do that, I want to have minimum If. else if statements.
ErrorObj Bean
public class ErrObj{
private String errorMessage;
private String errorCode;
private boolean errorFlag;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public boolean isErrorFlag() {
return errorFlag;
}
public void setErrorFlag(boolean errorFlag) {
this.errorFlag = errorFlag;
}
}
Below is the class where I am validating the Bean
Assume, im using some static methods of Custom util class which return boolean depending upon if a field is valid or not.
public class ValidateMyBean{
ErrObj errObj = new ErrObj();
if(!CustomUtils.isValid(myBean.getProp1))
{
// set some error conditions
errObj.errorCode("123");
errobj.setErrorMessage("validation 1 Failed");
}
else if(!CustomUtils.isValid(myBean.getProp2))
{
}
..........so on
}
So, if my bean has 10 properties and I have to validate each property against lets say 3 validator methods, I don't want to write multiple "if - elseif" statements or write mutliple "if" statements with return statement at the end of each if statement, in case of any error.
Is there any cleanser way or there are some frameworks which can help me reach the desired result?
PS:This Java application is using Spring Core framework and is a webservice application and not a MVC application.
There are many validation utils. You can check this example:
Spring MVC: How to perform validation?
There is also a jsr spec about it: JSR-303
http://beanvalidation.org/1.0/spec/
Enjoy
Accessing Java Beans using JSP:
Using JSP writing a java bean program becomes more easier.
The useBean action declares a JavaBean for use in a JSP. Once declared, the bean becomes a scripting variable that can be accessed by both scripting elements and other custom tags used in the JSP. The full syntax for the useBean tag is as follows:
<jsp:useBean id="bean's name" scope="bean's scope" typeSpec/>
Here values for the scope attribute could be page, request, session or application based on your requirement. The value of the id attribute may be any value as a long as it is a unique name among other useBean declarations in the same JSP.
Following example shows its simple usage:
<html>
<head>
<title>useBean Example</title>
</head>
<body>
<jsp:useBean id="date" class="java.util.Date" />
<p>The date/time is <%= date %>
</body>
</html>
This would produce following result:
The date/time is Thu Sep 30 11:18:11 GST 2010

struts2. Object fron jsp to action

First of all I'm newbie in Struts.
I've a class:
public class Articulo {
private int codigo;
private String descripcion;
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
}
which is populated with values in a dispatcher. In the dispatcher I've
private Articulo articulo;
.......
public Articulo getArticulo() {
return articulo;
}
public void setArticulo(Articulo articulo) {
this.articulo = articulo;
}
There is also a JSP with
<s:property value="articulo"/>
which read ok the articulo. Also works articulo
<s:property value="articulo.codigo"/>
But now I want from that jsp forward the entire object articulo to another action.
I can do
<s:hidden name="articulo.codigo" value="%{articulo.codigo}"/>
<s:hidden name="articulo.descripcion" value="%{articulo.descripcion}"/>
and that works fine, but is there anyway to do something like
<s:hidden name="articulo" value="%{articulo}"/>
So, is there anyway to get the object from JSP without setting all the properties of it?
there are 2 points:
Problem: you can't transfer object using <s:hidden />, all the parameter, what are transfered with HTTP should be string. Since you cannot convert this object to String, you can't transfer it using HTTP either.
Solution: You can put your object into session, so that you can access it anytime you want. here is an EXAMPLE
Yes, you can transfer object in two ways either by parameter or store it in session and access it whenever you need it.
<jsp:forward page="URL" >
<jsp:param name="ParamName1" value="YourObject" />
</jsp:forward>
Visit here for more detail.
http://www.gulland.com/courses/jsp/actions/forward
Keeping the object information in sessions is usually the preferred method.
But an alternative option is to create your own Type Converter.
Create a type converter by extending StrutsTypeConverter. The
Converter's role is to convert a String to an Object and an Object to
a String.
By doing so, you could so something like <s:hidden name="articulo" value="%{articulo}"/>
Keep in mind this method is insecure as the object values will be printed out as String in the hidden tag and can be seen through the browser.
But the advantage is that this method works across different sessions if you have a need for such a thing.

Categories

Resources