Reputation: 653
So I am building a site where someone puts a post and people can make comments to the post and people can make comments to those comments -- nested comments, if you will. Post creation: works, the initials responses/comments: works, but for some reason when I fill out the form add the nested comment, I get this error:
WARN 52874 --- [io-8080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'codes.optiko.oc.model.Comment'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'Adding my comment to a response'; nested exception is java.lang.NumberFormatException: For input string: "Addingmycommenttoaresponse"]
The following is my bean/model:
package codes.optiko.oc.model;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import java.sql.Timestamp;
@Entity
@Table(name = "comments")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(nullable = false, columnDefinition = "text")
private String comment;
// foreign key: many comments to one user
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
// foreign key: many comments to one response
@ManyToOne
@JoinColumn(name = "response_id")
private Response response;
// time stamps are sql-oriented
@Column
@CreationTimestamp
private Timestamp createDate;
@Column
@UpdateTimestamp
private Timestamp updateDate;
//************** CONSTRUCTORS ********************
// empty constructor
public Comment(){
}
public Comment(long id){
this.id = id;
}
public Comment(long id, String comment){
this.id = id;
this.comment = comment;
}
public Comment(long id, String comment, User user){
this.id = id;
this.comment = comment;
this.user = user;
}
public Comment(long id, String comment, User user, Response response){
this.id = id;
this.comment = comment;
this.user = user;
this.response = response;
}
public Comment(long id, String comment, User user, Response response, Timestamp createDate){
this.id = id;
this.comment = comment;
this.user = user;
this.response = response;
this.createDate = createDate;
}
public Comment(long id, String comment, User user, Response response, Timestamp createDate, Timestamp updateDate){
this.id = id;
this.comment = comment;
this.user = user;
this.response = response;
this.createDate = createDate;
this.updateDate = updateDate;
}
//************** GETTERS and SETTERS ********************
// getters and setters
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getBody() {
return comment;
}
public void setBody(String body) {
this.comment = comment;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Timestamp getDate() {
return createDate;
}
public void setDate(Timestamp date) {
this.createDate = createDate;
}
public Timestamp getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Timestamp updateDate) {
this.updateDate = updateDate;
}
public Response getResponse() {
return response;
}
public void setResponse(Response response) {
this.response = response;
}
public Timestamp getCreateDate() {
return createDate;
}
public void setCreateDate(Timestamp createDate) {
this.createDate = createDate;
}
}
The following is my controller (creating the comment):
@PostMapping("/posts/{post_id}/response/{response_id}/create-comment")
public String createResponse(@PathVariable long post_id, @PathVariable long response_id, @ModelAttribute Comment comment) {
Response response = responseRepo.getOne(response_id);
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
comment.setResponse(response);
comment.setUser(user);
comment.setCreateDate(new Timestamp(System.currentTimeMillis()));
commentRepo.save(comment);
return "redirect:/posts/" + post_id;
}
The following is my controller (For displaying a single post -- where people can add comments):
@GetMapping("/posts/{id}")
public String viewPost(@PathVariable long id, Model model) {
model.addAttribute("post", postRepo.getPostById(id));
model.addAttribute("responses", responseRepo.findByPostId(id));
model.addAttribute("response", new Response());
model.addAttribute("comments", commentRepo.findByResponseId(id));
model.addAttribute("comment", new Comment());
return "posts/show";
}
The following is my view:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:replace="partials/partials :: head ('Show Question')"></head>
<body>
<nav th:replace="partials/partials :: navbar"></nav>
<div class="container">
<h2 th:text="${post.title}"></h2>
<p style="padding-left: 2rem;" th:utext="${post.description}"></p>
<p style="padding-left: 2rem;" th:text="${post.updateDate}"></p>
<p style="padding-left: 2rem;" th:text="${post.user.username}"></p>
<div th:unless="${#lists.isEmpty(responses)}">
<h3>Responses:</h3>
<!-- Display video responses -->
<div class="post-div mb-3" th:each="res : ${responses}">
<p th:text="'Posted by: ' + ${post.user.username}"></p>
<div class="video-responsive" th:utext="${res.video}"></div>
<!-- Display comments for video responses -->
<div th:unless="${#lists.isEmpty(comments)}">
<div class="post-div mb-3" th:each="com : ${comments}">
<p th:text="${com.comment}"></p>
</div>
</div>
<!-- Add a comment -->
<div sec:authorize="isAuthenticated()">
<button class="add-comment btn btn-primary">Add a Comment</button>
<form th:action="@{|/posts/${post.id}/response/${res.id}/create-comment|}" th:method="post" th:object="${comment}" class="comment-form">
<div class="form-group">
<label for="comment">Comment:</label>
<textarea class="form-control" id="comment" th:field="*{comment}"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Comment</button>
</form>
</div>
<div sec:authorize="!isAuthenticated()">
<p class="font-weight-bold">Please <a href="/login">log in</a> or <a href="/register">register</a> to add a comment.</p>
</div>
</div>
</div>
<!-- Add a video response -->
<div sec:authorize="isAuthenticated()">
<button class="add-video-response btn btn-primary">Add a Video Response</button>
<form th:action="@{|/posts/${post.id}/create-response|}" th:method="post" th:object="${response}" class="video-response-form">
<div class="form-group">
<label for="video">Video Embed URL:<br><span class="small">(YouTube, Vimeo, DailyMotion, etc...)</span></label>
<textarea class="form-control" id="video" th:field="*{video}"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Video Response</button>
</form>
</div>
<div sec:authorize="!isAuthenticated()">
<p class="font-weight-bold">Please <a href="/login">log in</a> or <a href="/register">register</a> to add a video response.</p>
</div>
</div>
<standard_scripts th:replace="partials/partials :: footer">
</standard_scripts>
</body>
</html>
I tried having it print out to the console whatever is sent to the controller when they submit, but it seems like it errors out before even doing anything. I have been trying to figure this out for hours now, and have exhausted all of what I know to try and resolve the issue.
Thank you in advanced!
Upvotes: 0
Views: 2813
Reputation: 499
Note: Solution found in comments. Reposting as answer so it can be marked as solution
Change the name of the Field Comment#comment
. There is most likely a mixup in the html where it sends the comment
string back to the function instead of the Comment
object
Upvotes: 1