You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC中如何将嵌套List对象绑定到JSP表单?解决属性不可读异常

Fixing NotReadablePropertyException & Binding Nested Answer Lists in Spring MVC

Hey there! Let’s work through this issue together—this NotReadablePropertyException when binding nested lists is super common in Spring MVC, and I’ve sorted it out plenty of times. Here’s a step-by-step breakdown of what to check and fix:

1. Ensure Your Model Classes Have Initialized Collections

Spring can’t bind to a null list—you need to initialize nested collections upfront so the framework can access and modify them. Add initialization in your constructors or lazy-load in getters:

public class Assessment {
    private List<Question> questions;

    // Initialize the list in the constructor
    public Assessment() {
        this.questions = new ArrayList<>();
    }

    // Getter/Setter (follow JavaBean rules strictly!)
    public List<Question> getQuestions() {
        return questions;
    }

    public void setQuestions(List<Question> questions) {
        this.questions = questions;
    }
}

public class Question {
    private String questionText;
    private List<Answer> answers;

    public Question() {
        this.answers = new ArrayList<>();
    }

    // Getter/Setter for questionText and answers
    public List<Answer> getAnswers() {
        return answers;
    }

    public void setAnswers(List<Answer> answers) {
        this.answers = answers;
    }
}

public class Answer {
    private String text;
    private boolean isCorrect; // For boolean fields, use isXxx() for getters

    // Getter/Setter
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public boolean isCorrect() { // Correct getter for boolean type
        return isCorrect;
    }

    public void setCorrect(boolean isCorrect) { // Setter matches the property logic
        this.isCorrect = isCorrect;
    }
}

2. Correctly Format JSP Form Paths for Nested Lists

Spring uses index notation ([index]) to bind collection elements. Make sure your form paths match the nested structure exactly, and use JSTL’s varStatus to track indices:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<form:form modelAttribute="assessment" method="POST" action="/admin/save-assessment">
    <!-- Loop through questions -->
    <c:forEach items="${assessment.questions}" var="question" varStatus="qStatus">
        <div class="question-container">
            <label>Question Text:</label>
            <form:input path="questions[${qStatus.index}].questionText" />

            <!-- Loop through answers for this question -->
            <c:forEach items="${question.answers}" var="answer" varStatus="aStatus">
                <div class="answer-container">
                    <label>Answer Option:</label>
                    <form:input path="questions[${qStatus.index}].answers[${aStatus.index}].text" />
                    <form:checkbox path="questions[${qStatus.index}].answers[${aStatus.index}].isCorrect" />
                    <span>Correct Answer?</span>
                </div>
            </c:forEach>
        </div>
    </c:forEach>

    <button type="submit">Save Assessment</button>
</form:form>

3. Initialize the Full Model in Your Controller

Before rendering the form, populate your model with empty (or default) instances of Question and Answer—this gives Spring something to bind to:

@Controller
@RequestMapping("/admin")
public class AssessmentController {

    @GetMapping("/create-assessment")
    public String showCreateForm(Model model) {
        // Create a new assessment with one question and two answers (adjust as needed)
        Assessment assessment = new Assessment();
        Question initialQuestion = new Question();
        initialQuestion.getAnswers().add(new Answer());
        initialQuestion.getAnswers().add(new Answer());
        assessment.getQuestions().add(initialQuestion);

        // Add the assessment to the model
        model.addAttribute("assessment", assessment);
        return "admin/create-assessment";
    }

    @PostMapping("/save-assessment")
    public String saveAssessment(@ModelAttribute("assessment") Assessment assessment) {
        // Your save logic here (persist to DB, etc.)
        return "redirect:/admin/assessments";
    }

    // Optional: Handle dynamic collection growth (if users add more answers/questions)
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // Allow Spring to auto-grow collections when new elements are added dynamically
        binder.setAutoGrowNestedPaths(true);
        binder.setAutoGrowCollectionLimit(50); // Set a reasonable limit for your use case
    }
}

4. Double-Check JavaBean Compliance

Even if you think your getters/setters are correct, verify these rules:

  • Getters for non-boolean fields start with getXxx() (e.g., getText())
  • Getters for boolean primitive fields start with isXxx() (e.g., isCorrect())
  • Setters start with setXxx() and take a single parameter matching the field type
  • Property names are case-sensitive—make sure your JSP paths match the exact field names in your model classes (e.g., answers vs answer will cause errors)

5. Troubleshooting Dynamic Answer Addition

If you let admins add more answers dynamically (via JavaScript), make sure new input elements use the correct index sequence. For example, if a question already has 2 answers, the next one should use answers[2].text as the path. Spring requires continuous indices by default—if you need to skip indices (e.g., delete an answer), enable allowListIndexOverflow in your @InitBinder:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setAutoGrowNestedPaths(true);
    binder.setAutoGrowCollectionLimit(50);
    binder.setAllowListIndexOverflow(true); // Allow non-continuous indices
}

By following these steps, you should eliminate the NotReadablePropertyException and get your nested Answer List binding working smoothly.

内容的提问来源于stack exchange,提问作者moffeltje

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:25:44