Spring form doesn't submit to database correctly - java

I have a form where a user fills everything out in a settings page. All of it works except two fields. I'm not sure if it's the form or Controller or my table set up.
Here are the forms that aren't working.
<form:input path="minimumCost" type="text" class="form-control" id="exampleInputAmount" placeholder=""></form:input>
and
<form:input path="rate" type="text" class="form-control" id="exampleInputAmount" placeholder=""></form:input>
but this one DOES work
<form:input path="houseSize" type="text" class="form-control" id="exampleInputAmount" placeholder=""></form:input>
Here is the JPA i configured with them
#Column(name = "minimum_Cost")
private String minimumCost;
#Column(name = "rate")
private String rate;
#Column(name = "house_size")
private String houseSize;
public String getMinimumCost() {
return minimumCost;
}
public void setMinimumCost(String minimumCost) {
this.minimumCost = minimumCost;
}
public String getRate() {
return rate;
}
public void setRate(String rate) {
this.rate = rate;
}
public String getHouseSize() {
return houseSize;
}
public void setHouseSize(String houseSize) {
this.houseSize = houseSize;
}
Why are the minimumCost and rate showing up as null and houseSize works? They're all in the same form so it's not like they're being left out.

remove id="exampleInputAmount" and try it again~

Related

Invalid property 'xxx' of bean class. Does the return type of the getter match the parameter type of the setter?

I am aware that this question has been asked before but after looking through all of the examples, non of the solutions helped me.
I am simply trying to render a video form on my application via spring controller, but I keep
getting the aforementioned error on every field except two. Below is my html
<form th:action="#{/upload-video}" method="POST" enctype="multipart/form-data" th:object="${video}">
<input id="i_file" type="file" name="file" accept="video/*">
<div class="video_container">
<label for="video_name">Video Name</label>
<input class="textInput" id="video_name" type="text" th:field="*{videoName}" placeholder="Example: image.png">
<label for="videoDesc">Video Description</label>
<input id="videoDesc" type="text" placeholder="Enter a description..." th:field="*{video_Description}">
<label for="file_path">File Path</label>
<input id="file_path" class="file_path_input textInput" type="text" placeholder="File Path..."><br>
<video src="">
Enter a video...
</video>
</div>
<button type="submit">Upload</button>
</form>
The error is now being generated on the videoDescription input tag. Below is my GET controller:
#RequestMapping(value = "/upload-video", method = RequestMethod.GET)
private String uploadVideoPage(Model model) {
model.addAttribute("video", new Video());
return "upload-video";
}
Here is my video class:
#Entity()
#Table(name = "user_videos")
public class Video {
#Id
#GeneratedValue
private Long videoId;
private String videoName;
private String videoTagLine;
private String video_Description;
private Date uploadDate;
#Transient
private String uploadDateStr;
public String getVideoName() {
return videoName;
}
public void setVideoName(String videoName) {
this.videoName = videoName;
}
public String getVideoTagLine() {
return videoTagLine;
}
public void setVideoTagLine(String videoTagLine) {
this.videoTagLine = videoTagLine;
}
public String getVideo_Description() {
return video_Description;
}
public void setVideo_Description(String videoDescription) {
this.video_Description = videoDescription;
}
public Date getUploadDate() {
return uploadDate;
}
public void setUploadDate(Date uploadDate) {
this.uploadDate = uploadDate;
}
public String getUploadDateStr() {
return uploadDateStr;
}
public void setUploadDateStr(String uploadDateStr) {
this.uploadDateStr = uploadDateStr;
}
}
I've google and googled and googled and non of the solutions have worked. Any help would be appreciated.

How to access values from List<MyObject> something; created with thymleaf

Im trying to access the data from the controller stored like this but i dont know how:
*{regDatas[__1__].firstname}
I have a Wrapper class
public class RegDatas {
private List<RegData> regDatas;
public List<RegData> getRegDatas() {
return regDatas;
}
public void setRegDatas(List<RegData> regDatas) {
this.regDatas =regDatas;
}
}
My class to store values
public class RegData {
private String firstname;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
I stored some values with thymeleaf from input fields like this
<input required="required" th:class="${'checkboxDisabled2'}" type="text" th:field="*{regDatas[__1__].firstname}"/>
<input required="required" th:class="${'checkboxDisabled1'}" type="text" th:field="*{regDatas[__0__].firstname}"/>
and my Controller
public String meinestammdaten(#ModelAttribute RegDatas regDatas, Model model) {
//access values sotres in regDatas.. how?
}
You can use model.addAttribute(name, value) and access in html using tymeleaf like below code in your controller
public String meinestammdaten(#ModelAttribute RegDatas regDatas, Model model) {
model.addAttribute("firstName", regDatas.getFirstname());
return "html file"
}
Please change html file to according your file name
And in your thymeleaf
<input required="required" th:class="${'checkboxDisabled2'}" type="text" th:field="${firstName}"/>
If you have the list and adding that list in the model.addAttribute() of regDatas then you can use th:each="regdata : ${regdata}"
For more info about thymeleafe visit the link http://www.thymeleaf.org/doc/articles/springmvcaccessdata.html

Unable to get updated values in a dynamically created form using Spring Boot and Thymeleaf

I have created a dynamic form in Thymeleaf which populates feedbacks from all users in a table format on the UI. The form is first called when the GET Api of the controller gets hit. Relevant code for the same is given below :
allfeedbacks.html
<h2>Dynamic form</h2>
<form action="#" th:action="#{/updatefb}" th:object="${feedbacklist}"
method="post">
<table>
<tr>
<th>Message</th>
<th>Status</th>
<th>Comments</th>
</tr>
<tr th:each="feedback : ${feedbacklist.myfbList}">
<td th:text="${feedback.message}" th:field="${feedback.message}">The
first name</td>
<td><select>
<option value="Pending"
th:selected="${feedback.status == 'Pending'}">Pending</option>
<option value="In Process"
th:selected="${feedback.status == 'In Process'}">In
Process</option>
<option value="Done" th:selected="${feedback.status == 'Done'}">Done</option>
</select></td>
<td><input type="text" placeholder="Enter Comment Here"
name="comments" th:text="${feedback.comment}"
th:field="${feedback.comment}" /></td>
</tr>
</table>
<button type="submit">Submit</button>
</form>
Basically I have created two beans, one is the Feedback.java bean while the other is FeedbackList.java bean. Code for the same is given below :
Feedback.java
#Entity
#Table(name = "feedback")
public class Feedback implements Serializable {
private static final long serialVersionUID = -3009157732242241606L;
#Id
private String id;
public String getId() {
return id;
}
public String getMessage() {
return message;
}
public String getStatus() {
return status;
}
public String getComment() {
return comment;
}
#Column(name = "message")
private String message;
#Column(name = "status")
private String status;
#Column(name = "comment")
private String comment;
public Feedback() {
}
public Feedback(String message, String status) {
this.message = message;
this.status = status;
this.id = UUID.randomUUID().toString();
}
FeedbackList.java
public class FeedbackList {
ArrayList<Feedback> myfbList;
public ArrayList<Feedback> getMyfbList() {
return myfbList;
}
public void setMyfbList(ArrayList<Feedback> myfbList) {
this.myfbList = myfbList;
}
}
Relevant code from my Controller class is as follows :
#RequestMapping(value = "/getAll", method = RequestMethod.GET)
public String getAllFeedbacks(#Valid FeedbackList feedbacklist,
BindingResult bindingResult, Model model) {
ArrayList<Feedback> fbarray = new ArrayList<>();
for (Feedback fb : repository.findAll()) {
fbarray.add(fb);
}
feedbacklist.setMyfbList(fbarray);
model.addAttribute("feedback", new Feedback());
model.addAttribute("feedbacklist", feedbacklist);
return "allfeedbacks";
}
#RequestMapping(value = "/updatefb", method = RequestMethod.POST)
public String updatefbStatus(#Valid FeedbackList feedbacklist,
BindingResult
bindingResult, Model model) {
//feedbacklist is coming as NULL below
for (Feedback fb : feedbacklist.getMyfbList()) {
System.out.println(fb.getComment());
System.out.println(fb.getMessage());
System.out.println(fb.getStatus());
}
// Code to update the database with the new status and comment would go
// here
return "result";
}
The form is getting properly rendered on the UI when I fire the Get request, however, when I make some changes in the form and submit it ( POST ), feedbacklist is coming as NULL. Could anyone please guide me with this ?
To use a list inside a form with Thymeleaf is a little bit more tricky, you need to use an specific syntax, here i show you an example.
<tr th:each="feedback : ${feedbacklist.myfbList}">
<td th:field="*{myfbList[__${feedbackStat.index}__].message}">The
first name
</td>
...//Same for others fields
</tr>
In thymeleaf you have to use the Stat object to say the array position where you want to set the value, also as normal fields inside an object you have to use the '*' notation.

org.springframework.beans.NullValueInNestedPathException: auto-grow nested property path in Spring MVC 3.2.8

I have a project based in Spring Web model-view-controller (MVC) framework. The version of the Spring Web model-view-controller (MVC) framework is 3.2.8.
This class
public class DeviceForm {
Device device;
List<String> selectedItems = Collections.emptyList();
public DeviceForm() {
super();
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
}
and this
public class Device implements java.io.Serializable {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CRITERIA")
private BaseCriteria criteria;
public BaseCriteria getCriteria() {
return criteria;
}
public void setCriteria(BaseCriteria criteria) {
this.criteria = criteria;
}
}
and this
#Entity
#Table(name = "CRITERIA")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
#SequenceGenerator(name = "seqCriteria", sequenceName = "SEQ_CRITERIA", allocationSize = 1)
public abstract class BaseCriteria {
public BaseCriteria() {
super();
}
private Long id;
private String code;
private Date adoptionDate;
private Date expirationDate;
#Transient
public abstract String getGroupKey();
#Transient
public abstract Long getGroupId();
#Transient
public abstract String getRefColumnName();
#Id
#Column(name = "ID", unique = true, nullable = true)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqCriteria")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Column(name = "ADOPTION_DATE")
#Temporal(TemporalType.TIMESTAMP)
public Date getAdoptionDate() {
return adoptionDate;
}
public void setAdoptionDate(Date adoptionDate) {
this.adoptionDate = adoptionDate;
}
#Column(name = "EXPIRATION_DATE")
#Temporal(TemporalType.TIMESTAMP)
public Date getExpirationDate() {
return expirationDate;
}
#Transient
public boolean isExpired() {
return getExpirationDate().before(new Date());
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
#Override
public String toString() {
return "BaseCriteria [id=" + id + ", code=" + code + ", adoptionDate="
+ adoptionDate + ", expirationDate=" + expirationDate + "]";
}
}
and the JSP
<form:form commandName="deviceForm"
name="deviceForm"
id="deviceFormId"
method="post"
action="${contextPath}/newdesign/manage/device/${deviceForm.device.id}"
htmlEscape="yes">
<div class="col-sm-6 text-right">
<button class="btn btn-primary" type="submit">Save device</button>
</div>
</div>
<c:forEach items="${deviceForm.device.productGroup.criteria}" var="criteria">
<div class="row">
<div class="col-md-3">
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
<label for="basic-url">Criteria:</label>
<input value="${criteria.code}" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Adoption date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.adoptionDate}" />" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Expiration Date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.expirationDate}" />" disabled="disabled" class="form-control"/>
</div>
</div>
</c:forEach>
</form:form>
The controller:
/**
* #throws Exception
*
*/
#RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.GET})
public String viewDevicesWithStatus(
#ModelAttribute("deviceForm") DeviceForm deviceForm,
#PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(appId, true);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
/**
* #throws Exception
*
*/
#RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.POST})
public String saveDevicesWithStatus(
#ModelAttribute("deviceForm") DeviceForm deviceForm,
#PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(deviceForm.getDevice().getId());
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
//TODO: audit
device.updateDevice(deviceForm.getDevice());
manageLicenseService.saveDevice(device);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
But I got following error when I submitted the form, on GET method I got same page without error
org.springframework.beans.NullValueInNestedPathException: Invalid property 'device.criteria' of bean class [com.tdk.iot.controller.newdesign.manage.DeviceForm]: Could not instantiate property type [com.tdk.iot.domain.criteria.BaseCriteria] to auto-grow nested property path: java.lang.InstantiationException
You get the error because in your form you have this:
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
and in your POST handler you have this:
public String saveDevicesWithStatus(#ModelAttribute("deviceForm") DeviceForm deviceForm){
}
which means that the MVC framework will try to automatically set the property
deviceForm.device.criteria.id.
Now, because there is no existing DeviceForm in any scope then it will create a new one and of course device.getCriteria() returns null,
hence the exception.
You may think that the DeviceForm you created and populated in the GET handler will be used however Spring MVC is stateless so you
would need to store it in Session scope between requests for it to be re-used or otherwise rework your logic.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args
.... Given the above example where can theinstance come from? There
are several options.....[in the absence of any other option] It may
be instantiated using its default constructor
A better approach however is to change your form to be as below:
<form:radiobutton path="device.criteria" value="${criteria.id}"/>
and register a converter that would convert the submitted parameter and bind the corresponding entity instance.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert
#Component
public class StringToCriteriaConverter implements Converter<String, BaseCriteria> {
#Autowired
private CriteriaService service;
//source is the ID passed by the page
public BaseCriteria convert(String source) {
// lookup and return item with corresponding ID from the database
}
}

JSP - error getting class enum type property

I have a problem accesing public enum class properties inside my JSP page. I am able to access all other's invite class properties except invite.status attribute. I am doing something wrong, but i just can't figure why it is wrong and how i can access my returned list's enum values. Thanks for your help solving my issue!
Error what I get The class ...domain.jpa.meeting.Invite' does not have the property status.
This is JPA class that I have
#Entity
public class Invite implements PersistentEntity {
#Id #GeneratedValue
private Long id;
#ManyToOne
private User inviter;
#ManyToOne
private User invitee;
#ManyToOne
private Meeting meeting;
/**
* Date when this invite has been created
*/
private Date created;
// #Column(nullable=false, length=1)
// #Enumerated(EnumType.STRING)
private InviteStatus status;
public Long getId() {
return id;
}
public User getInviter() {
return inviter;
}
public void setInviter(User inviter) {
this.inviter = inviter;
}
public User getInvitee() {
return invitee;
}
public void setInvitee(User invitee) {
this.invitee = invitee;
}
public Meeting getMeeting() {
return meeting;
}
public void setMeeting(Meeting meeting) {
this.meeting = meeting;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public InviteStatus getInviteStatus() {
return status;
}
public void setInviteStatus(InviteStatus status) {
this.status = status;
}
}
This is enum type public class that i have
/**
* Values for tracking invite status
*/
public enum InviteStatus {
// invite is created and invitee have not responded yet
CREATED,
// invitee accepted this invite
ACCEPTED,
// invitee declined this invite
DECLINED
}
I am saving in database such way (with success as EnumType.ORDINAL)
// adding invites (table invite)
Invite invite = new Invite();
invite.setInviter(creator);
User invitee = jpaDAO.getById(User.class, Long.parseLong(friends[i]));
invite.setInvitee(invitee);
invite.setInviteStatus(InviteStatus.CREATED); //CREATED = 0, ACCEPTED = 1, ..
Date dateNow = new Date(); //yyyy-MM-dd HH:mm:ss
invite.setCreated(dateNow);
Meeting meeting = jpaDAO.getById(Meeting.class, meetingId);
invite.setMeeting(meeting);
jpaDAO.save(invite);
And i have a method which retrieves invites from database.
#SuppressWarnings({ "unchecked", "null" })
public List<Invite> getUserInvites(Long userId){
// getting invites for current user with status CREATED
Query query = jpaDAO.getEntityManager().createNamedQuery(JPQConst.InviteJpq.QUERY_GET_BY_USER);
query.setParameter("userId", userId);
List<Invite> invites = (List<Invite>) query.getResultList();
return invites;
}
Inside controller it looks like this:
/**
* Display Notifications tab
*/
#RequestMapping(value = "/home/notifications", method = RequestMethod.GET)
public String displayNotifications(ModelMap model, HttpSession session) {
User user = getCurrentUser(session);
List<Invite> invites = notificationService.getUserInvites(user.getId());
model.addAttribute("invites", invites);
return "home";
}
Method itself works, and I am able to access all invite's property fields except status property inside jsp.
<c:forEach var="meeting" items="${inviteeMeetings}">
<c:forEach var="invite" items="${invites}">
<c:choose>
<c:when test="${meeting.id == invite.meeting.id}">
<tr>
<td width="150px" align="center">
<c:out value="${meeting.startTime}" />
</td>
<td width="396px">
<c:out value="${meeting.title}" />
</td>
<td width="96px">
<c:out value="${invite.status}" />
<form action="../meeting/attendance" method="post">
<input type="hidden" name="venue" value="${meeting.id}" />
<input type="submit" name="attendance" value="attend" />
<input type="submit" name="attendance" value="reject" />
</form>
</td>
</tr>
</c:when>
</c:choose>
</c:forEach>
</c:forEach>
Effectively, your class does not have such property. It does have the inviteStatus property.
public InviteStatus getInviteStatus() {
return status;
}
PROPERTIES ARE BASED IN GETTERS. The name of the internal value that stores the data is not relevant.

Categories