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.
Related
Sorry if the title is a bit confusing, I didn't really know how to word what I wanted to ask.
Basically, I am making an api call to a database that returns data as such:
[{"profiles":{"testexample":{"addresses":[{"city":"","street1":"","street2":"apt 320"}],"addressType":"HOME","city":"","dateOfBirth":"","emailAddress1":"","emailAddress2":"","emailAddresses":[{"email":"","preferred":1,"type":"BUSINESS"},{"email":"","preferred":0,"type":"PERSONAL"}],"firstName":"","lastName":"","phoneNumber":"","phoneNumbers":[],"phoneType":"HOME","postalCode":"","preferred":1,"street1":"","street2":""}]
The code I have below works fine when the database returns a non-empty profiles {}. I have the following Java classes that looks like the following:
public class Account {
#JsonProperty("profiles")
private Profiles profiles;
#JsonProperty("profiles")
public Profiles getProfiles() {
return profiles;
}
#JsonProperty("testexample")
public void setProfiles(Profiles profiles) {
this.profiles = profiles;
}
}
public class Profiles {
#JsonProperty("testexample")
private Profile testExample;
#JsonProperty("testexample")
public Profile getTestExample() {
return testExample;
}
#JsonProperty("testexample")
public void setTestExample(Profile testExample) {
this.testExample = testExample;
}
}
public class Profile {
#JsonProperty("dateOfBirth")
private String dateOfBirth;
#JsonProperty("dateOfBirth")
public String getDateOfBirth() {
return dateOfBirth;
}
#JsonProperty("dateOfBirth")
public void setDateOfBirth(String dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
}
So what I want to do when I get the data is check whether the getProfiles() returns empty, so I don't make the calls to anything within that object.
Please note, for the sake of simplicity I omitted other parts of the classes to focus primarily on what I wanted
This is what I have so far, and it works when the profiles {} is not empty
Account response = access.lookup(id, type); //This is to grab the response from the database, which is working.
response.getProfiles(); //This is the part that works when it has a profiles {} not empty, but fails on empty.
So what happens is that I don't get an error for response.getProfiles(), but if I tried to do response.getProfiles().getDateOfBirth(), it won't work because it will give a null pointer exception since the dateOfBirth isn't there.
I want to avoid calling anything within response.getProfiles() by skipping it if it's empty.
You need some basic null checking. The most basic way is to assign a new variable and check.
Profiles profiles = account.getProfiles();
if(profiles != null) {
//dosomething with profiles.getDateOfBirth()
}
The more "modern" functional Java way would be to use the Optional class.
String dateOfBirth = Optional.ofNullable(account.getProfiles())
.map(profile -> profile.getDateOfBirth)
.orElse(null);
(A note about your example: In the Account class, you have this.
#JsonProperty("testexample")
public void setProfiles(Profiles profiles) {
this.profiles = profiles;
}
Which appears to be an incorrect #JsonProperty annotation and might be causing some problems.
That said, it is not necessary to annotate the getters and setters. The one annotation on the field is sufficient.)
Say I have this custom Java class Club.java:
public class Club
{
private Integer id;
private String name;
/* getters, setters */
}
Now the jquery-ui autocomplete code:
var autocomplete = $('#clubs').autocomplete({
source: currentClubs
}).data("autocomplete");
if (autocomplete != undefined)
{
autocomplete._renderItem = function(ul, item) {
return $("<li>").attr('data-value', item.value).append(item.label).appendTo(ul);
};
}
where currentClubs is an array of JSON objects which correspond to the above Java class Club ( { value : club.id, label : club.name } ).
This works fine until I submit the form.
I am using Spring MVC Framework, here is my controller:
#RequestMapping(value = "someMapping", method = RequestMethod.POST)
public String someMethod(HttpSession session, Model model, #ModelAttribute("someForm") SomeForm form)
{
jada jada ...
}
where SomeForm contains a field private Club clubChoice. I would like to map my selected JSON Object to that field. How can I achieve this? Many thanks.
Well, it took me another 10 minutes to figure out how to do this.
I changed this part:
var autocomplete = $('#clubs').autocomplete({
source: currentClubs
}).data("autocomplete");
to this:
var autocomplete = $('#clubs').autocomplete({
source: currentClubs,
select: function (event, ui) {
$('#club-id').val(ui.item.id);
}
}).data("autocomplete");
where clubId is a hidden input:
<form:input path="club.name" name="club-name" id="club-name" />
<form:hidden path="club.id" name="club-id" id="club-id" />
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
I have a Stripes form using an Action bean.
I can store the data without any problem out of the form, but I did not find out how to prepopulate the form's data.
I have simplified my example to show what's not working.
My code under #Before is without any effect: the data dont go into the form.
How should I manage this approach?
myform.jsp:
...
<stripes:form beanclass="UserActionBean">
...
<stripes:text name="user" />
<stripes:submit name="store" value="Save" />
...
</stripes:form>
...
ActionBean:
public class UserActionBean implements ActionBean {
private String user;
#Before
public void init() {
user = "myuser";
}
#DefaultHandler
public Resolution store() {
...
}
}
You will need public getters and setters for Stripes to be able to read the value.
Although usually I would use the #DefaultHandler for the get, and then create a new handler for the save e.g. #HandlesEvent(value = "save") public Resolution save () {...
This might be crude, but I used a getter like Scary Wombat said and initialized the variable in the ActionBean. Or you could set its value in your handler that does the initial page display.
#Validate(required = true, on = {
"proceed"
})
private String tumblrUrl= "xyz.tumblr.com";
...
public String getTumblrUrl() {
return this.tumblrUrl;
}
public void setTumblrUrl(final String tumblrUrl) {
this.tumblrUrl = tumblrUrl;
}
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.