Getting java.lang.NumberFormatException when displaying data in JSP page - java

I am using Hibernate and Spring MVC. I am trying to fetch information from two tables and display it in a jsp page . Here are my tables:
Table Name : student
student_id studentName
1. Jason Stathum
Table Name : studentdetails
studentDetailsid FatherName MotherName student_id
1 Mr.X Mrs. Y 1
In my JSP page I am trying to display data like this:
Sl# Student Father Mother
1 Jason Stathum Mr.X Mrs.Y
When I run my application to see the data I get the following error message:
HTTP Status 500 - An exception occurred processing JSP page /WEB-INF/views/studentlist.jsp at line 29
root cause
java.lang.NumberFormatException: For input string: "FatherName"
java.lang.NumberFormatException.forInputString(Unknown Source)
java.lang.Integer.parseInt(Unknown Source)
java.lang.Integer.parseInt(Unknown Source).... and many other lines...
I have included my codes below, Could you please tell me what I am doing wrong?
Thank you very much
Entity: Student
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="student_id", nullable= false)
private Integer studentId;
private String studentName;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="student_id", referencedColumnName="student_id")
private List<StudentDetails> studentDetails = new ArrayList<StudentDetails>();
// Getters and Setters
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public List<StudentDetails> getStudentDetails() {
return studentDetails;
}
public void setStudentDetails(List<StudentDetails> studentDetails) {
this.studentDetails = studentDetails;
}
Entity : StudentDetails
#Entity
#Table(name = "studentDetails")
public class StudentDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer studentDetailsId;
private String FatherName;
private String MotherName;
// Getters and Setters
public Integer getStudentDetailsId() {
return studentDetailsId;
}
public void setStudentDetailsId(Integer studentDetailsId) {
this.studentDetailsId = studentDetailsId;
}
public String getFatherName() {
return FatherName;
}
public void setFatherName(String fatherName) {
FatherName = fatherName;
}
public String getMotherName() {
return MotherName;
}
public void setMotherName(String motherName) {
MotherName = motherName;
}
Controller
#RequestMapping(value="studentlist", method = RequestMethod.GET)
public String getRecords(Model map)
{
List<Student> student = studentService.getAll();
map.addAttribute("student", student);
return "studentlist";
}
StudentDaoImpl
#Override
#SuppressWarnings("unchecked")
public List<Student> getAll() {
return getSessionFactory().openSession().createQuery("FROM Student").list();
}
JSP Page: studentlist
<c:if test="${!empty student}">
<table class="studentTable">
<tr>
<th>Sl#</th>
<th>Name</th>
<th>Father</th>
<th>Mother</th>
</tr>
<c:set var="count" value="0" scope="page" />
<c:forEach items="${student}" var="row">
<c:set var="count" value="${count + 1}" scope="page"/>
<tr>
<td>${count}</td>
<td>${row.studentName}</td>
<td>${row.studentDetails.FatherName}</td> <--- this is line 29
<td>${row.studentDetails.MotherName}</td>
</tr>
</c:forEach>
</table>
</c:if>

The problem is your trying to reference a property of an List object.
${row.studentDetails} = List<StudentDetails>
JSTL is trying to convert FatherName to a number so it can get that index in List<StudentDetails>.
To fix this you could do ${row.studentDetails[0].fatherName} or you could put a method in Student called something like getDefaultStudentData() that would return the first or "preffered" student details object then reference it like ${row.defaultStudentData.fatherName}. Or of course you could change your output to deal with multiple student details per Student ☺

In your JSP your variable row represents the Student object. So when you say row.studentDetails you are getting java.util.List now when you try to access anything on this list, then JSP assumes you are trying to fetch an element of the list using the provided index.
So it is like list.indexNumber, so JSP assumes FatherName and MotherName as number and tries to convert them to integer and gets the exception.
To fix this you have to iterate through the list:
<c:forEach items="${srow.studentDetails}" var="details">
${details.FatherName}
${details.MotherName}
</c:forEach>
Update:
As per naming convention you have to access the properties using details.fatherName and details.motherName
The standard way of declaring Java beans is to name the properties as fatherName instead of FatherName
private String fatherName;
private String motherName;
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public String getMotherName() {
return motherName;
}
public void setMotherName(String motherName) {
this.motherName = motherName;
}

Related

Thymeleaf form passing all but one inputs to java controller

My thymeleaf form has three inputs, when I submit it my controller is receiving the second and the third, but not the first one (first input is null)
I have similar forms and method to add records to a MySQL database which work with no problems.
I have diplayed the two first inputs in my controller, first (Id of the entity) is null, second is well informed
Here is my form:
addDepartment.html
<br/>
<form th:action="#{/university/addDepartment}"
th:object="${department}" method="POST">
Department Name
<input type="text" th:field="*{deptName}" />
<br/>
Department building
<input type="text" th:field="*{building}" />
<br/>
Budget
<input type="number" th:field="*{budget}" th:value=0/>
<br/>
<input type="submit" value="Add" />
</form>
<!-- Check if errorMessage is not null and not empty -->
<div th:if="${errorMessage}" th:utext="${errorMessage}"
style="color:red;font-style:italic;">
...
</div>
And my controller
// ADD a department to the database
// Show the addDepartment page
#RequestMapping(value= { "university/addDepartment" }, method = RequestMethod.GET)
public String showAddDepartment(Model model) {
Department department = new Department();
model.addAttribute("department", department);
return "addDepartment";
}
// Add the department to the database
#RequestMapping(value = { "university/addDepartment" }, method = RequestMethod.POST)
public String saveDepartment(Model model, //
#ModelAttribute("department")
#Validated Department department) {
System.out.println("DEPARTMENT: " + department.toString());
String deptName = department.getDeptName();
System.out.println("DEPARTMENT NAME: " + deptName);
String building = department.getBuilding();
System.out.println("BUILDING: " + building);
int budget = department.getBudget();
if (deptName != null && deptName.length() > 0 //
&& building != null && building.length() > 0 //
&& budget >= 0) {
Department newDepartment = new Department(deptName, building, budget);
departmentrepo.save(newDepartment);
return "redirect:/university/departmentList";
}
Object errorMessage = "All fields are mantatory";
model.addAttribute("errorMessage", errorMessage );
return "addDepartment";
}
Here is the Department class:
#Entity
#Table(name="department") // This annotation is needed only if the
table has a different name to this class
#EntityListeners(AuditingEntityListener.class)
public class Department {
#Id
private String deptName;
private String building;
private int budget;
//Constructors
public Department() {
}
public Department(String deptName, String building, int budget) {
this.deptName = deptName;
this.building = building;
this.budget = budget;
}
...GETTERS and SETTERS
The deptName is always null, but the other two inputs are ok
DEPARTMENT NAME: null
BUILDING: Main
UPDATE: I think I found the solution, but if someone can explain the reason...
I just passed the deptName in a #RequestParam annotation.
#RequestMapping(value = { "university/addDepartment" }, method =
RequestMethod.POST)
public String saveDepartment(Model model, //
#ModelAttribute("department") Department department,
#RequestParam("deptName") String deptName) {
//String deptName = department.getDeptName();
System.out.println("DEPARTMENT NAME: " + deptName);
String building = department.getBuilding();
System.out.println("BUILDING: " + building);
int budget = department.getBudget();
if (deptName != null && deptName.length() > 0 //
&& building != null && building.length() > 0 //
&& budget >= 0) {
Department newDepartment = new Department(deptName, building, budget);
departmentrepo.save(newDepartment);
return "redirect:/university/departmentList";
}
Object errorMessage = "All fields are mantatory";
model.addAttribute("errorMessage", errorMessage );
return "addDepartment";
}x`
There are a few issues with this code, but the first thing to try is removing the #Id annotation from your deptName property. Create a Long (or Integer) id property and annotate this instead. You can more simply call the department name property name too.
You will also want to make sure that you have the getters and setters done correctly, or more advisable - just use Project Lombok to get rid of extra text and potential for mistakes.
#Entity
#Table
#Data //see Project Lombok
public class Department {
#Id
private Long id;
private String name;
private String building;
private int budget; //I'd consider making this more precise by using BigDecimal
}
For your controller, let's more simply try this to see whether it is still breaking.
#GetMapping("/university/addDepartment")
public String showAddDepartment(Model model) {
model.addAttribute("department", new Department());
return "addDepartment";
}
#PostMapping("/university/addDepartment")
public String saveDepartment(#ModelAttribute("department") Department department) {
System.out.println("name="+department.getName()); //use a logger if you have one available
return "addDepartment";
}
In your form, you only need the th: notation if you want Thymeleaf to evaluate the logic. So you can change th:value=0 to value=0 if you really intend this.

How to map Form Parameter with Hibernate Entity Class in Spring-MVC Controller [duplicate]

This question already has an answer here:
Binding child object on submit spring mvc
(1 answer)
Closed 5 years ago.
I am new at Hibernate/JPA and I am trying to get form parameter with hibernate entity class. There was no problem with it until when I tried to get parameter with Entity class that has relationship with other class. For example;
Controller:
#RequestMapping(value = "/addProduct", method = RequestMethod.POST)
public String addProduct(Model model, Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Entity class:
#Entity
#Table(name = "products")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private Category category;
#Column(name = "name")
private String name;
#Column(name = "price")
private String price;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Category class :
#Entity
#Table(name = "categories")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The program cannot set 'category'. Because category is not type like int, string.. I am realize the problem. But I cannot find solution to mapping parameters with Entity class. Is there any way to solve this. Or should I use #RequestParam to get parameters one-by-one instead of mapping parameters with entity class.
UPDATE
I just change category to category.id in my .jsp page and it solved my problem.
old code
<form>
...
<select class="form-control" name="category">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
new code
<form>
...
<select class="form-control" name="category.id">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
Please show us your form mapping,
Till then can could try with, change path in <form:select>/<form:input> tag to category.id and category.name
have a look at my another answer
I will suggest don't expose your Entity in the View, try to get form data in DTO, then convert to entity..
One way to do that is by creating a custom Spring Converter. So lets say you will be passing your entity's Id as a path variable, and your converter implementation would get that product object for you.
In your Controller you will need to do the following:
#RequestMapping(value = "/addProduct/{id}", method = RequestMethod.POST)
public String addProduct(Model model, #PathVariable("id") Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Your Converter would look something like this:
import org.springframework.core.convert.converter.Converter;
public class StringToProductConverter implements Converter<String, Product> {
...
#Override
public Product convert(String id) {
Product product = databaseService.getProduct(id);
...
return product;
}
And don't forget to register your Converter either programmatically or by XML depending on your Spring version you're working on.

Spring MVC: The request sent by the client was syntactically incorrect when creating a new entity record

Good afternoon,
I am newbie to Spring MVC. I'm stuck with the following error while running my project "The request sent by the client was syntactically incorrect."
My project has two entities, Team and Country which have a ManyToOne relationship. Both these entities map tables created in mysql database.
I started the project with only the Team entity, and sucessfuly created my classes (DAO, controller, services, etc) and jsp to create new teams.
Now, I created the class Country to relate both entities and I added a dropdown list in the "add-team-form.jsp" to select the country of the new team. This page is correctly displayed (all countries appear in the dropdown list), however, when I click "submit" to create the new team, I get the error "The request sent by the client was syntactically incorrect."
Can you please help me to identify my error? I'm guessing it's in the "add-team-form.jsp".
1 - Entity Team:
#Entity
#Table(name="teams")
public class Team implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name", length = 40, nullable = false)
private String name;
#Column(name = "rating", length = 6, nullable = false)
private Integer rating;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_country", nullable = false)
private Country country;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getRating() {
return rating;
}
public void setRating(Integer rating) {
this.rating = rating;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
}
2 - Entity Country:
#Entity
#Table(name = "countries")
public class Country implements Serializable{
#Id
#Column(name= "id_country", length = 6)
private String idCountry;
#Column(name = "name", length = 255, nullable = false)
private String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "country")
private List<Team> teams;
public String getIdCountry() {
return idCountry;
}
public void setIdCountry(String idCountry) {
this.idCountry = idCountry;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My Team DAO
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public void addTeam(Team team) {
getCurrentSession().save(team);
}
}
My Team Service
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
#Autowired
private TeamDAO teamDAO;
public void addTeam(Team team) {
teamDAO.addTeam(team);
}
My Team Controller
#Controller
#RequestMapping(value="/team")
public class TeamController {
#Autowired
private TeamService teamService;
#Autowired
private FilterService filterService;
#RequestMapping(value="/add", method=RequestMethod.GET)
public ModelAndView addTeamPage() {
ModelAndView modelAndView = new ModelAndView("add-team-form");
modelAndView.addObject("team", new Team());
return modelAndView;
}
#RequestMapping(value="/add", method=RequestMethod.POST)
public ModelAndView addingTeam(#ModelAttribute Team team) {
ModelAndView modelAndView = new ModelAndView("home");
teamService.addTeam(team);
String message = "Team was successfully added.";
modelAndView.addObject("message", message);
return modelAndView;
}
#ModelAttribute("countryList")
public Map<String, String> getCountryList(){
Map<String, String> countryList = filterService.getCountries();
return countryList;
}
...
}
My "add-team-form.jsp"
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Add team page</title>
</head>
<body>
<h1>Add team page</h1>
<form:form method="POST"
modelAttribute="team"
action="${pageContext.request.contextPath}/team/add.html">
<table>
<tbody>
<tr>
<td>Name:</td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td>Rating:</td>
<td><form:input path="rating" /></td>
</tr>
<tr>
<td><label>Country</label></td>
<td>
<form:select path="country.idCountry">
<form:options items="${countryList}" />
</form:select>
</td>
<tr>
<td><input type="submit" value="Add" /></td>
<td></td>
</tr>
</tbody>
</table>
</form:form>
</body>
</html>
There is no error showing in the console of eclipse, but here is the error im receiving from the browser:
HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect.
Apache Tomcat/7.0.47
There's a couple of problems I can see here - you are posting to add/team/add.html and not hitting your post handler. You don't need the action attribute as you're posting to the same endpoint;
<form:form method="POST" modelAttribute="team" >
Secondly your are injecting the countries as a map, so these are ID/display values which works great for key/value pairs and for binding a value to a string field. In this case, Spring is trying to bind your country ID (String) to the team.country(Country) field which will fail. To help Spring out you need a databinder; in your controller add;
#InitBinder
public void initBinder (WebDataBinder binder) {
binder.registerCustomEditor(Country.class, new CountryEditor());
}
and create the property editor class;
public class CountryEditor extends PropertyEditorSupport {
#Override
public void setValue(Object value) {
super.setValue(value);
}
public String getAsText() {
if (getValue() == null) return null;
return ((Country) getValue()).getName();
};
public void setAsText(String text) throws IllegalArgumentException {
if (text != null) {
Country country = // something like filterService.getCountryById(text);
setValue(country);
}
};
}
There's more information in the Spring documentation
The error you are receiving generally happens if a parameter is missing or is in a different format and cannot be converted to the expected type.Check the values being passed to the Team object.You can either log the request and response or set the log level to "DEBUG",this will display the exact error in logs.

Getting a list of objects in model and implementing into ng-repeat

I have a webapp and two models which I would like to use. One model is Trainees and another one is TraineeStatus. I would like to get an array or a list of TraineeStatus inside Trainees and then pass it to AngularJS view an display it inside select method, what is the best approach to do it?
Trainees.java
#Entity
public class Trainees {
#Id
#GeneratedValue
private int traineesID;
private int groupsID;
#ManyToOne
private TraineeStatus traineestatus;
private int customersID;
private String name;
private String surname;
private String phoneDetails;
private String email;
public Trainees(){
}
public Trainees(String name, String surname, String phoneDetails, String email, int id, int groupsID, TraineeStatus traineestatus, int customersID) {
super();
this.name = name;
this.surname = surname;
this.email = email;
this.phoneDetails = phoneDetails;
this.groupsID = groupsID;
this.traineestatus = traineestatus;
this.customersID = customersID;
}
//getters and setters
#Override
public boolean equals(Object object) {
if (object instanceof Trainees){
Trainees contact = (Trainees) object;
return contact.traineesID == traineesID;
}
return false;
}
#Override
public int hashCode() {
return traineesID;
}
}
TraineeStatus.java
#Entity
#Table(name="traineeStatus")
public class TraineeStatus {
#Id
#GeneratedValue
private int traineeStatusId;
private String value;
public TraineeStatus(){
}
public TraineeStatus(String value, int id) {
super();
this.value = value;
}
//getters and setters
#Override
public boolean equals(Object object) {
if (object instanceof TraineeStatus){
TraineeStatus value = (TraineeStatus) object;
return value.traineeStatusId == traineeStatusId;
}
return false;
}
#Override
public int hashCode() {
return traineeStatusId;
}
}
My view:
<div class="input-append">
<select
required
ng-model="contact.traineestatus"
name="traineestatus.id"
placeholder="<spring:message code='sample.status'/> ">
<option ng-repeat="trainee in contact.traineestatus" value="{{trainee.id}}">{{trainee.value}}</option>
</select>
</div>
<div class="input-append">
<label>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.traineestatus.id.$error.required">
<spring:message code="required"/>
</span>
</label>
</div>
Currently with contact.traineestatus returns one object with id and value, but I would like to get an array.
I am trying to utilize the object, so I would have a select function, where it displays the value and would save the Id and save it in the Trainees table.
Is there a way to utilize this object and use it in my select? Thanks in regards!
This is a little difficult to explain, so I will try to keep it simple.
First of all you need to have in mind the the list of TraineeStatus is not going to be retrieved in the same request has the contact/trainees list, you will need a separate HTTP request to get that list.
The same way you have ContactRepository to get all the Trainees records, you will need a TraineeStatusRepository to get all the TraineeStatus records. Then, on one of your Services you would need a method to get the TraineeStatus list, like this:
private List<TraineeStatus> findAllTraineeStatus() {
return traineeStatusRepository.findAll();
}
After that you will need to define an HTTP API to access that list (i.e. GET http://example.com/traineeStatus). The idea is probably the same you have to retrieve the ContactList.
Then, on your AngularJS app, you would need to use a function to load the list of TraineeStatus. For example:
$scope.getTraineeStatus = function () {
// assuming the HTTP API is: GET http://example.com/traineeStatus
$http.get('http://example.com/traineeStatus', config)
.success(function (data) {
$scope.traineeStatus = data;
})
.error(function (err) {
// handle error
});
}
And then loop through the $scope.traineeStatus property on the ng-repeat:
<select
required
ng-model="contact.traineestatus"
name="traineestatus.id"
placeholder="<spring:message code='sample.status'/> ">
<option ng-repeat="status in traineeStatus" value="{{status.id}}">{{status.value}}</option>
</select>

LazyInitialization Exception with Spring and Hibernate

I think i'm missing something fundamental about how Hibernate works, specifically with lazy loading. My problem is debugging, as I'm not sure if this is a Hibernate problem or a Spring problem in disguise. I thought I would ask here before doing some major refactoring.
I have two Entities. One holds a collection of the other in a OneToMany relationship. For my web page I wish to grab all of the first entity, and subsequently grab the set of associated entities for each and display them.
I believe my problem is this: I use a JpaTemplate to find all entities. This works fine, however because of Lazy loading I do not get the associated set of related entities. In my view (jsp) I want access to this set, but of course it is null because it is being lazy loaded. Now, i'm getting a LazyInitialization exception stating that the transaction has ended. To me this makes sense, of course the transaction should be over by now. The thing is, how can the assoicated set ever be lazy loaded if the transaction is over?
Entity Classes:
#Entity
public class LearningEntry implements Serializable {
private Long id;
String imagePath = "";
Set<Sample> samples = null;
//------------------------------
// Constructors
//------------------------------
public LearningEntry(){
imagePath = "";
samples = new HashSet<Sample>();
}
//------------------------------
// Instance Methods
//------------------------------
public void addSample(Sample s){
samples.add(s);
}
public void removeSample(Sample s){
samples.remove(s);
}
//------------------------------
// Setters and Getters
//------------------------------
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//#Column(name = "wisi_LE_IMAGEPATH", length = 100, nullable = false)
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
// TODO - ONly works with fetch type EAGER
//#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
public Set<Sample> getSamples() {
return samples;
}
public void setSamples(Set<Sample> samples) {
this.samples = samples;
}
}
Sample Entity
#Entity
public class Sample implements Serializable {
private Long id;
Date creationDate;
String audioFileLocation;
Integer votes;
String description;
public Sample(){
creationDate = new Date();
audioFileLocation = "";
votes = 0;
description = "";
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAudioFileLocation() {
return audioFileLocation;
}
public void setAudioFileLocation(String audioFileLocation) {
this.audioFileLocation = audioFileLocation;
}
#Temporal(TemporalType.DATE)
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getVotes() {
return votes;
}
public void setVotes(Integer votes) {
this.votes = votes;
}
}
DAO Classes:
LearningEntryDAO
#Transactional
public class JpaLearningEntryDAO implements LearningEntryDAO{
private JpaTemplate jpaTemplate;
public JpaLearningEntryDAO(){
}
public void setJpaTemplate(JpaTemplate jpaTemplate){
this.jpaTemplate = jpaTemplate;
}
#Override
//#Transactional
public void delete(Long leId) {
LearningEntry dp = jpaTemplate.find(LearningEntry.class, leId);
jpaTemplate.remove(dp);
}
#Override
#SuppressWarnings("unchecked")
//#Transactional
public List<LearningEntry> findAll() {
return jpaTemplate.find("from LearningEntry");
}
#Override
//#Transactional
public LearningEntry findById(Long leId) {
return jpaTemplate.find(LearningEntry.class, leId);
}
#Override
//#Transactional
public LearningEntry store(LearningEntry dp) {
return jpaTemplate.merge(dp);
}
#Override
#SuppressWarnings("unchecked")
//#Transactional
public void deleteAll(){
throw new RuntimeException("deleteAll not implemented");
}
}
Sample DAO
#Transactional
public class JpaSampleDAO implements SampleDAO{
private JpaTemplate jpaTemplate;
public JpaSampleDAO(){}
public void setJpaTemplate(JpaTemplate jpaTemplate){
this.jpaTemplate = jpaTemplate;
}
#Override
//#Transactional
public void delete(Long sampleId) {
Sample dp = jpaTemplate.find(Sample.class, sampleId);
jpaTemplate.remove(dp);
}
#Override
#SuppressWarnings("unchecked")
public List<Sample> findAll() {
return jpaTemplate.find("from Sample");
}
#Override
public Sample findById(Long sampleId) {
return jpaTemplate.find(Sample.class, sampleId);
}
#Override
public Sample store(Sample dp) {
return jpaTemplate.merge(dp);
}
#Override
#SuppressWarnings("unchecked")
public void deleteAll(){
throw new RuntimeException("deleteAll not implemented");
}
}
Controller
#RequestMapping(value = "/index.htm", method = RequestMethod.GET)
public ModelAndView sayHello(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Map<String, Object> model = new HashMap<String, Object>();
List<LearningEntry> le = learningEntryService.getLearningEntries();
model.put("learningEntries", le);
return new ModelAndView("main", model);
}
View
<section id="content" class="body">
<ol id="posts-list" class="hfeed">
<c:forEach items="${learningEntries}" var="learningEntry">
<li>
<table class="wisiEntry">
<tr>
<td class="pictureCell">
<img class="wisiEntry-pic" src="${learningEntry.imagePath}" />
</td>
<td class="previousNextCell"
<div class="wisiEntry-nextSampleButton">Next</div>
<div class="wisiEntry-previousSampleButton">Previous</div>
<br />
<div class="wisiEntry-addTagButton">Tag</div>
<div class="wisiEntry-addCommentButton">Comment</div>
<br />
<div class="wisiEntry-uploadButton">Upload</div>
</td>
<td>
<!-- ERROR HAPPENS HERE. Samples should not be null -->
<c:forEach items="${learningEntry.samples}" var="sample" varStatus = "status">
<table class="sampleEntry" ${status.first ? '' : 'style = "display:none"'}>
<tr>
<td class="sampleCell">
<p class="description">
${sample.description}
</p>
<audio src="${sample.audioFileLocation}" controls>
Your browser does not support the <code>audio</code> element.
</audio>
</td>
<td class="voteCell">
<img class="upVote" src="/images/upArrow.jpeg" />
<span class="voteNumber">${sample.votes}</span>
<img class="downVote" src="/images/downArrow.jpeg" />
</td>
</tr>
</table>
</c:forEach>
</td>
</tr>
</table>
</li>
</c:forEach>
</ol><!-- /#posts-list -->
</section><!-- /#content -->
I hope you are using findAll() method down the call. You can load all the associated samples by modifying your method like below.
public List<LearningEntry> findAll() {
List<LearningEntry> entries = jpaTemplate.find("from LearningEntry");
for(LearningEntry entry : entries){
entry.getSamples().size();
}
return entries;
}
Or, as you already know, you can also achieve this by changing fetch to FetchType.EAGER. But this might not suit you in all cases. Therefore, former way is better.
Or you might like to do no change anywhere, and define another method to get all the samples based on LearningEntry, this way you will be able to fire up an AJAX call on some event. But that might not suit here in this case.
Thanks to Vinegar for providing a working answer (upvoted).
I decided to add this answer that has also worked for me. I took this approach because I may want to make separate ajax calls in the future. In other words, I can ask for the LearningEntry in one transaction, than ask for its samples some time down the road.
#Transactional
public Set<Sample> getSamplesForLearningEntry(LearningEntry le) {
// Reload the le from the database so it is not transient:
LearningEntry le = leDAO.store(le);
le.getSamples.size();
return le.getSamples();
}
Most frameworks offer the 'open session in view' pattern. See https://www.hibernate.org/43.html:
The solution, in two-tiered systems,
with the action execution, data access
through the Session, and the rendering
of the view all in the same virtual
machine, is to keep the Session open
until the view has been rendered.
For data that is read often and hardly ever updated, query caching can help too. This reduces the load on the database, but increases memory usage. Hibernate can be configured to do this for you.

Categories

Resources