Hello everyone, I have
org.springframework.beans.NotReadablePropertyException: Invalid property 'expensename' of bean class [java.lang.String]:
while working on a Spring boot app. The error occurred after I created a spring form and used the path attribute to access the the entity field name "expensename" but I got the White Label Error Page below when I tried to run my expense.jsp.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Mar 26 03:49:39 WAT 2022
There was an unexpected error (type=Internal Server Error, status=500).
Invalid property 'expensename' of bean class [java.lang.String]: Bean property 'expensename' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
org.springframework.beans.NotReadablePropertyException: Invalid property 'expensename' of bean class [java.lang.String]: Bean property 'expensename' 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.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:627)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:617)
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:158)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:199)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:149)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:139)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:122)
at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:460)
at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:357)
at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:87)
at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:83)
at org.apache.jsp.WEB_002dINF.views.expense_jsp._jspx_meth_form_005finput_005f0(expense_jsp.java:282)
at org.apache.jsp.WEB_002dINF.views.expense_jsp._jspx_meth_form_005fform_005f0(expense_jsp.java:232)
at org.apache.jsp.WEB_002dINF.views.expense_jsp._jspService(expense_jsp.java:157)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:466)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:379)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:327)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
What I have tried:
The problem came from here.
<h1>Add Expense</h1>
<form:form action="${contextRoot}/save" method="post" modelAttribute="expense">
<form:input path="expensename" placerholder="Enter Expense Name"/>
<form:textarea path="note" placerholder="Enter note (optional)"/>
<button type="submit">Add Expense</button>
</form:form>
My Controller
@Controller
public class MasterController {
@Autowired
ExpenseService expenseService;
@RequestMapping("/")
public ModelAndView home() {
ModelAndView mav = new ModelAndView("home");
mav.addObject("message", "List of expenses");
List<Expense> expenses = expenseService.findAll();
mav.addObject("expenses", expenses);
return mav;
}
@RequestMapping("/expense")
public ModelAndView addexpense() {
ModelAndView mav = new ModelAndView("expense");
mav.addObject("expense", "new Expense()");
return mav;
}
@RequestMapping(value= "/expense", method=RequestMethod.POST)
public String save(@ModelAttribute("expense") Expense expense) {
expenseService.save(expense);
return "redirect:/";
}
}
My Expense.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextRoot" value="${pageContext.request.contextPath}" />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Add Expense</h1>
<form:form action="${contextRoot}/save" method="post" modelAttribute="expense">
<form:input path="expensename" placerholder="Enter Expense Name"/>
<form:textarea path="note" placerholder="Enter note (optional)"/>
<button type="submit">Add Expense</button>
</form:form>
</body>
</html>
My Entity - Expense.java
@Entity
@Table(name="tbl_expenses")
@ToString
public class Expense {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(name="description")
private String expensename;
private BigDecimal amount;
private String note;
private Long createdAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getExpensename() {
return expensename;
}
public void setExpensename(String expensename) {
this.expensename = expensename;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Long getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Long createdAt) {
this.createdAt = createdAt;
}
@Override
public String toString() {
return "Expense [id=" + id + ", expensename=" + expensename + ", amount=" + amount + ", note=" + note
+ ", createdAt=" + createdAt + "]";
}
}
I used Eclipse to create my Getters and Setters. Please how can I overcome this hurdle ? Thanks for any help. Also, please note that the code that I'm using came from this Youtube tutorial on Spring boot -
Spring Boot Masterclass 12 - Create expense form - YouTube[
^]