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".
Related
I am currently making an application that lets you create students, and then mark them absent. I want to be able to do this by adding it into a separate table called AbsentStudents. But with the jparepository or the crudreposotroy don't give me these options.
I tried to create a new entity that was a replica of the students entity, then make the dao equal the findbyid of the student. it looked like this:
dao.equals(repo.findById(id));
Index.jsp:
<body>
<p> Add a student into the database:<p>
<form action ="addStudent">
<input type = "text" name = "ID"><br>
<input type = "text" name = "Name"><br>
<input type = "text" name = "Teacher"><br>
<input type = "submit">
</form>
<p> Mark a Student Absent<p>
<form action ="markAbsent">
<input type = "text" name = "ID"><br>
<input type = "submit">
</form>
</body>
</html>
Then the absentStudent, which is the same as student
#Entity
#Getter
#Setter
public class AbsentStudent
{
#Id
private int id;
public int getId() {
return id;
}
}
I then created the dao of both the student and absent.
Finally, here is the controller. I left the autowired out.
#RequestMapping("/addStudent")
public String addStudent(Student student) {
repo.save(student);
return "index.jsp";
}
#RequestMapping("/markAbsent")
public ModelAndView markAbsent(#RequestParam int id) {
ModelAndView mv = new ModelAndView();
dao.equals(repo.findById(id));
mv.setViewName("absent.jsp");
mv.addObject(dao);
return mv;
}
}
I was expecting a page in the end, which would fetch all the absent students from the database, and post them on a single page. But, I get an error page.
the data didn't copy from student to absent student.
I want to be able to do this by adding it into a separate table called AbsentStudents. But with the jparepository or the crudreposotroy don't give me these options.
Maybe #Query annotation inside dao (repository) interface will help with your problem ( https://www.baeldung.com/spring-data-jpa-query )
I'm trying to learn Spring and other related technologies during summer break by developing a simple web application, however Thymeleaf hinders my progress.
The program is based on two entity classes:
Invoice.java:
#Entity
public class Invoice {
#Id
private String invoiceId;
#NotNull
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate issueDate;
//getters and setters
}
TrasportOrder.java:
#Entity
public class TransportOrder {
#Id
private int number;
#NotNull
private BigDecimal value;
#ManyToOne
private Invoice invoice;
//getters and setters
}
I'm getting a form for adding invoices using a method from InvoiceController:
#GetMapping(path = "/add")
public String getForm(Model model) {
model.addAttribute("unusedOrders", service.getInvoiceOrders(null));
model.addAttribute("orders", new ArrayList<TransportOrder>());
model.addAttribute("invoice", new Invoice());
return "addInvoice";
}
unusedOrders is a list of orders that a user can choose from,
orders is a list that is meant to contain orders chosen by user
invoice is just an invoice that's being created in the form.
My form contains text and data inputs regarding the invoice, and then comes a multiple select for the orders:
<!-- I used to define th:object here and used th:field in the inputs, however changed it to use th:value everywhere -->
<form action="/invoices/add" method="post">
<table>
<tr>
<th>
Invoice ID:
</th>
<th>
<input type="text" th:value="${invoice.invoiceId}" name="invoiceId"/>
</th>
</tr>
<tr>
<!-- a few other inputs -->
</tr>
<tr>
<th>
Orders:
</th>
<th>
<!-- problem may lie here -->
<select id="orders" th:value="${orders}" multiple="multiple">
<option th:each="unusedOrder: ${unusedOrders}"
th:value="${unusedOrder.number}"
th:text="${unusedOrder}">Unused orders to choose from</option>
</select>
</th>
</tr>
</table>
<button type="submit">Next</button>
</form>
I've read Thymeleaf docs and forums, as well as several SO questions, but they still leave me confused about how does th:object, th:field, th:value and others work with forms, and especially with multiple select tag.
On submit, the form sends a POST request to a method in the same controller:
#PostMapping(path = "/add")
public String addInvoice(#ModelAttribute Invoice invoice,
BindingResult result,
#ModelAttribute("orders") ArrayList<TransportOrder> orders,
Model model) {
//invoice and orders saving logic, etc.
return "viewInvoices";
}
My problem is that invoice is being properly retrieved from the from and persisted in the database, but orders list stays empty. I expect it to be populated with orders chosen in the form. I don't know, if it's because of #ModelAttribute annotation (I also tried #RequestAttribute without success), Thymeleaf tags, or anything else.
Okay, so I decided to fight for the answer once more, and fortunately I stumbled upon an answer.
Based on this tutorial, I created an wrapper class ChosenOrdersDTO:
public class ChosenOrdersDTO {
private List<TransportOrder> chosenOrders;
//constructor, getters, setters...
}
I added it to the first model (changed the getForm() method as following):
model.addAttribute("chosenOrders", new ChosenOrdersDTO(new ArrayList<>()));
In the form I used the th:field tag, similarly to previous fields:
<select id="orders" th:field="${chosenOrders.chosenOrders}" multiple="multiple">
And in the second controller I was able to retrieve the list wrapped in the ChosenOrdersDTO class as a #ModelAttribute:
#PostMapping(path = "/add")
public String addInvoice(#ModelAttribute Invoice invoice,
BindingResult
#ModelAttribute ChosenOrdersDTO chosenOrders,
Model model)
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.
I need to manually display data from database in jsp page. But it wont display.
My entity:
#Entity
#NamedQuery(name="Contact.getAll", query="SELECT c FROM Contact c")
public class Contact implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String login;
private String name;
private String surname;
getters/setters/equals/hashcode
Bean to manage jsp:
public class DisplayDataBean {
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("ContactsPU");
private EntityManager em = emf.createEntityManager();
private List<Contact> contacts = em.createNamedQuery("Contact.getAll", Contact.class).getResultList();
public List<Contact> getContacts() {
return contacts;
}
}
And jsp page fragment:
<c:forEach var="contact" items="${DisplayDataBean.contacts}">
<tr>
<td><c:out value="${contact.login}"/></td>
<td><c:out value="${contact.name}"/></td>
<td><c:out value="${contact.surname}"/></td>
</tr>
</c:forEach>
Can you please tell what can be wrong in here? Thanks in advance.
Also when i work with
<sql:query var="contacts" dataSource="jdbc/contactapplication">
SELECT * FROM contact;
</sql:query>
everything is fine.
Problem was that i didnt declare DisplayDataBean.
Solution is to add tag in jsp page:
<jsp:useBean id="displayBean" class="web.DisplayDataBean"/>
You are not declaring the variable contacts so that it is not showing, when you are using JSTL tag then you are using variable contacts.
I you are using Spring then please add this contacts variable to ModelMap so that it can be retrieve.
ModelMap mm = new ModelMap();
mm.put("contacts", values);
Or if you are using Servlet then just add this variable to response parameter.
request.setAttribute("contacts", "value");
You may have to provide a physical table name to your entity. I think case sensitivity may cause problems here ("contact" and "Contact" aren't necessarily considered the same).
Also, I'm not 100% sure, but the #NamedQuery may need to be enclosed into #NamedQueries - so the entity definition could start like this:
#Entity
#Table(name="contact")
#NamedQueries({
#NamedQuery(name="Contact.getAll", query="SELECT c FROM Contact c")
})
public class Contact implements Serializable {
// the rest of the class definition goes here...
If you have debugging enabled, you may be able to see if the query was actually issued or if it "failed" even before that.
By the way, when you say "it won't display", does it mean nothing is rendered by c:forEach? Does it render empty table, nulls or nothing at all? Example of the generated output could help.
I assume there are no exceptions visible in the console/log?
Hy guys, I've turning around a problem using Struts2.
Basically I've a form that the user can submit filling different fields. I would like to populate conditionally the right object with the properties insert by the user.
So for example, if the user fill the form in a intermediary way I would like to use the properties for to create an Intermediary object, instead if the user fill the request in entity way, i'll use the properties for to create the Entity object, ecc...
These object share the same interface Request.
Is there any way to use polimorphically properties for to create Intermediary or Entity object?
Suppose this is my two POJO:
public class Intermediary implements Request{
private String name;
private String surname;
private String code;
private String FiscalCode;
private String address;
...
/*Getters and setters */
....
}
public class Entity implements Request{
private String name;
private String surname;
private String code;
....
/*Getters and setters */
....
}
This could be my form into the jsp page:
<s:form action="fillRequest" id="formRichiesta" name="formRichiesta" method="post">
<s:radio id="tipoRichiedente" name="tipoRichiedente" list="richiedenti">
<label>Name</label><s:textfield name="name"/>
<label>Surname</label><s:textfield name="surname"/>
<label>code</label><s:textfield name="code"/>
<label>Adress</label><s:textfield name="adress"/>
<label>Fiscal Code</label><s:textfield name="fiscalCode"/>
</s:form>
<s:submit>
Basically my problem is that I can discover the kind of request the the user trying to fill only ofter submission and watching at the radiobutton state.
Is there any way to mapping the properties into the right object directly instead of creating one big object with all the form properties and then create the right implementation? for to map properties could I use the interface reference?
For example image my action:
public class RequestAction {
private Request request;
....
}
So in my jsp could I use:
<label>Name</label><s:textfield name="request.name"/>
Thanks in advance.