1
votes

I'm not understanding why when I attempt to use a modelAttributed form in with spring it's attempting to convert my String type variable to a Long type variable when it should just remain a String type. Only thing I suspect it's trying to do is fill the Id variable.

Failed to convert value of type 'java.lang.String' to required type'javaSpring.DojoOverflow.models.Questions'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'Why?'; nested exception is java.lang.NumberFormatException: For input string: "Why?"

//---------------------------------------------------
// My Model
@Entity
@Table(name="questions")
public class Questions {
    // Attributes
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @NotEmpty(message = "Ask a question!")
    private String question;
    @Column(updatable=false)
    private Date createdAt;
    private Date updatedAt;
    @OneToMany(mappedBy="question", fetch = FetchType.LAZY)
    private List<Answer> answers;
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable (
       name="questions_tags",
       joinColumns = @JoinColumn(name="question_id"),
       inverseJoinColumns = @JoinColumn(name="tag_id")  
    )
    @Size (max=3)
    @NotEmpty(message="Tag your question!")
    private List<Tag> tags;

// ------------------------------------- 
// My Controller Mapping
@PostMapping("/questions/new")
public String processQuestion(@Valid @ModelAttribute("question")Questions   question, BindingResult result) {
    if(result.hasErrors()) {
        return "newQuestion.jsp";
    }
    questionService.createQuestion(question);
    return "redirect:/";
}

//-----------------------------------------------
// My jsp
<body>
<div class="container">
<h1>What is your question?</h1>
<form:form action="/questions/new" method="post" modelAttribute="question">
    <div class="form-group">        
        <form:label path="question">Question</form:label>
        <form:textarea rows="5" class="question form-control" path="question"/>
        <span class="error"><form:errors path="question"/></span>
    </div>
    <div class="form-group">        
        <form:label path="tags">Tags</form:label>
        <form:input class="tags form-control" placeholder="Tags"   path="tags"/>
        <span class="error"><form:errors path="tags"/></span>
    </div>
    <button class="btn btn-secondary" type="submit">Submit</button>
</form:form>
<a href="/questions">Go Back</a>
</div>
</body> 
2
Are you sure that types of columns in database match types of your properties in entity class?Ivan
Database type for the question field where the error occurs is listed as varchar(255) in mysql.SomeCoder
So how could Java convert varchar to long? Either change column to NUMBER (or any other numeric integer type specific for your database) or change type for property to StringIvan
If you look at my entity, the question field is listed as a String and the corresponding field in MySql is varchar(255) so the types do match in those regards. I just don't understand why it's trying to convert when it shouldn't need to.SomeCoder
For some reason it's attempting to convert when processing the post.SomeCoder

2 Answers

0
votes

Looks like an incompletely initialized object. Check your createQuestion service method, and be sure each required field for Question is set before you pass it to the controller. That form alone doesn't have all the necessary fields.

0
votes

I suggest to apply MVVC pattern to separate your business object from your view object.

You expect to receive only strings from the view in your model attribute object.

Your entity object contains a list of tags and a list of answers => they are modeled differently and the usage of the same class is difficult, with many potential bugs.

In your case it is better to create.a separate view class only with strings and convert them to your entity object.

Example :

public class QuestionModelAttribute {
       private String tags;
       private String answers;
       .....
 }

and your method will receive:

@PostMapping("/questions/new")
public String processQuestion(@Valid @ModelAttribute("question") QuestionModelAttribute questionModelAttribute, BindingResult result) {
   Questions question = questionsService.convertQuestion(questionModelAttribute);
   questionService.save(question);
   ..
}

Your view will receive in the model a QuestionModelAttribute

<form:form action="/questions/new" method="post" modelAttribute="questionModelAttribute">

This pattern offers a healthy decoupling between the view and model.