Andrey Yaskulsky
Andrey Yaskulsky

Reputation: 2526

Spring MVC, capture List of objects like @ModelAttribute

I have Test class and i have jsp page that contains inputs binded to the list of tests objects. I want to take my list of tests back from my jsp with edited information. My Test Class is:

@Entity
@Table(name = "[NewMVC].[dbo].[Tests]")
public class Test {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id; 

    @Column(name = "testQuestion")
    private String testQuestion;

    @Column(name = "optionOne")
    private String optionOne;

    @Column(name = "optionTwo")
    private String optionTwo;

    @Column(name = "optionThree")
    private String optionThree;

    @Column(name = "subjectType")
    private int subjectType;

    @Column(name = "correctOptionNumber")
    private int correctOptionNumber; 
        //gets, sets...

And i have a jsp in which i can edit list with tests:

   <form:form action="saveTestsEdits" method="POST" modelAttribute = "testWrapper">

    <c:forEach items="${testWrapper.testList}" var="test" varStatus="i">
    <h2> Test number ${i.index+1} </h2>
    <form:hidden value="${test.id}" path = "testList[${i.index}].id" />
    <table>
        <tr><td>Test Question:</td> <td><form:input path = "testList[${i.index}].testQuestion" value = "${test.testQuestion}"/> </td></tr>
        <tr><td>Option one: </td> <td><form:input path = "testList[${i.index}].optionOne" value= "${test.optionOne}"/> </td>
        <td>        
        <c:choose>
        <c:when test="${test.correctOptionNumber == 1}"> <form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "1" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "1"/> </c:otherwise> 
        </c:choose> 
        </td>
        </tr>

        <tr><td>Option two: </td> <td><form:input path = "testList[${i.index}].optionTwo" value= "${test.optionTwo}"/> </td>
        <td>        
        <c:choose>
        <c:when test="${test.correctOptionNumber == 2}"> <form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "2" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "2"/> </c:otherwise> 
        </c:choose> 
        </td>
        </tr>


        <tr><td>Option three: </td> <td><form:input path = "testList[${i.index}].optionThree" value= "${test.optionThree}"/> </td>
        <td>        
        <c:choose>
        <c:when test="${test.correctOptionNumber == 3}"> <form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "3" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].correctOptionNumber" value = "3"/> </c:otherwise> 
        </c:choose> 
        </td>

        </tr>
        <tr><th>Subject type:</th></tr>
        <tr><td>Georaphy: </td> 
        <td>        
        <c:choose>
        <c:when test="${test.subjectType == 3}"> <form:radiobutton path = "testList[${i.index}].subjectType" value = "3" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].subjectType" value = "3"/></c:otherwise> 
        </c:choose> 
        </td>
        </tr>

        <tr><td>Mathematics: </td> 
        <td>        
        <c:choose>
        <c:when test="${test.subjectType == 4}"><form:radiobutton path = "testList[${i.index}].subjectType" value = "4" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].subjectType" value = "4"/></c:otherwise> 
        </c:choose> 
        </td>
        </tr>

        <tr><td>History: </td> 
        <td>        
        <c:choose>
        <c:when test="${test.subjectType == 5}"><form:radiobutton path = "testList[${i.index}].subjectType" value = "5" checked = "checked"/> </c:when>
        <c:otherwise><form:radiobutton path = "testList[${i.index}].subjectType" value = "5"/></c:otherwise> 
        </c:choose> 
        </td>
        </tr>

    </table>
    <br>        
    </c:forEach>
    <input type="submit" value="Submit" />
</form:form>
</body>
</html>

Actually i'm not sending to the page List clearly but i have a special class called TestWrapper which looks like:

public class TestWrapper {

    private List<Test> testList = null;

    public TestWrapper(List<Test> testList) {

        this.testList = testList;
    }

    public void setTestList(List<Test> testList) {

        this.testList = testList;
    }

    public List<Test> getTestList() {

        return testList;
    }

}

I tried to use:

@RequestMapping(value="/saveTestsEdits", method = RequestMethod.POST)
     public String register(@ModelAttribute("testWrapper")TestWrapper testWrapper , HttpServletRequest request)

But it gives me an exception:

SEVERE: Servlet.service() for servlet [appServlet] in context with path [/mvc] threw exception [Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.andrew.models.TestWrapper]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.andrew.models.TestWrapper.<init>()] with root cause
java.lang.NoSuchMethodException: com.andrew.models.TestWrapper.<init>()

Thank you very much!

Upvotes: 3

Views: 4522

Answers (1)

Viral Patel
Viral Patel

Reputation: 8601

The exception java.lang.NoSuchMethodException: xxx.<init>() is thrown by JVM when it is unable to instantiate an object of class xxx. In this case Spring coudln't instantiate TestWrapper class.

You have one list argument constructor but not the default one. Add one like below:

public class TestWrapper {

    public TestWrapper() {
    }
}

Upvotes: 5

Related Questions