I'm getting an error NotReadablePropertyException: Invalid property 'userIds' of bean class [...ListOfIds]... And I'm not sure why. If I remove the th:field attribute on the checkbox, the table fills in properly. I've tried with th:field="*{requestIds}" and th:field="*{requestIds.ids}"
What I'm trying to do is collect the list of ids from the selected checkboxes and pass them back to the controller for the post.
Form
public class ListOfIds {
List<Long> ids = new ArrayList<>();
public List<Long> getIds() { return ids; }
// I've tried both set methods by themselves and together.
public void setIds(List<Long> ids) { this.ids = ids; }
public void setIds(Long[] ids) { this.ids = Arrays.asList(ids); }
}
Request bean
public class Request {
long id;
String name;
String phone;
String email;
// Getters/Setters
}
Controller
#GetMapping("/myTable")
public ModelAndView getMyTable(ModelAndView mav) {
mav.setViewName("myTable");
List<Request> requests = service.getRequests();
mav.addObject("requests", requests);
mav.addObject("requestIds", new ListOfIds());
return mav;
}
#PostMapping("/myTable")
public ModelAndView postRequests(ModelAndView mav, #ModelAttribute("requestIds") ListOfIds ids) {
...
}
html page
...
<form method="post" th:action="#{/myTable}" th:object="${requestIds}">
<table class="table ...">
<thead>
<tr>
<th><input type="checkbox" class="selectall" data-target="requests-all"/></th>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr role="row" th:each="request : ${requests}">
<td>
<input type="checkbox" name="requestId" data-target="requests-all"
th:value="${request.id}" th:field="*{requestIds}"/>
</td>
<td th:text="${request.name}"></td>
<td th:text="${request.phone}"></td>
<td th:text="${request.email}"></td>
</tr>
</tbody>
</table>
<button class="btn btn-primary show-selected">Process</button>
</form>
...
<script>
$(document).ready(function() {
$('button').click(function(e) {
if !(confirm("Are you sure you wish to process these requests")) {
e.preventDefault();
}
});
});
</script>
...
So the answer is that name and th:field don't play nice together.
I made the following changes and it worked:
Controller
#PostMapping("/myTable")
public ModelAndView postRequests(ModelAndView mav,
#ModelAttribute("requestIds") Long[] ids) {
...
}
html
<form id="postMyTable" method="post" th:action="#{/myTable}">
<table ...
<input type="checkbox" name="requestId" data-target="requests-all"
th:value="${request.id}"/>
...
<script>
$(document).ready(function() {
$('button').click(function(e) {
if !(confirm("Are you sure you wish to process these requests")) {
e.preventDefault();
} else {
$("#postMyTable").submit();
}
});
});
</script>
Related
I'm currently developing an online banking application where you can buy stocks. It is being built with spring boot and the front-end is html/css.
I am using the YahooFinance API to get stock quotes but I need to refresh my page to get the live stock quotes, how can I automatically update the page every 30 seconds to get the new prices for each stock?
Also, is there a way I could implement this using Threads?
Banking Controller
#GetMapping("/banking/stocks")
public String stocks(Model model) {
model.addAttribute("stock", new StockDto());
try {
List<Stock> stocks = stockService.getDefaultStocks();
model.addAttribute("stocks", stocks);
} catch (IOException e) {
e.printStackTrace();
}
return "stocks.html";
}
StockServiceImpl:
#Service
public class StockServiceImpl implements StockService {
private String[] startingStocks = { "AAPL", "BABA", "MSFT", "AXP", "BA", "AMD", "TSLA", "MA", "SHOP", "GOOGL",
"KL" };
#Override
public Stock getStock(String stockName) throws IOException {
Stock stock = YahooFinance.get(stockName);
return stock;
}
#Override
public Map<String, Stock> getStock(String[] s) throws IOException {
Map<String, Stock> stocks = YahooFinance.get(s);
return stocks;
}
#Override
public List<Stock> getDefaultStocks() throws IOException {
Map<String, Stock> stocks = YahooFinance.get(startingStocks);
List<Stock> stockList = new ArrayList<Stock>();
for(String s : startingStocks) {
stockList.add(stocks.get(s));
}
return stockList;
}
}
HTML Page For Displaying Stocks:
<main class='main-content bgc-grey-100'>
<div id='mainContent'>
<div class="container-fluid">
<br>
<h4 class="c-grey-900 mT-10 mB-30">Stock Table</h4>
<form action="#" th:object="${stock}" th:action="#{/banking/stock-search}"
method="POST" class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search"
th:field="*{name}" placeholder="Search Stock"
aria-label="Search">
<button class="btn btn-outline-primary my-2 my-sm-0" type="submit">Search</button>
</form>
<br>
<div class="row">
<div class="col-md-12">
<div class="bgc-white bd bdrs-3 p-20 mB-20">
<table id="dataTable" class="table table-striped table-bordered"
cellspacing="0" width="100%">
<thead>
<tr>
<th>Ticker</th>
<th>Trade</th>
<th>Name</th>
<th>Price</th>
<th>(%) Change</th>
<th>Div Yield (%)</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Ticker</th>
<th>Trade</th>
<th>Name</th>
<th>Price</th>
<th>(%) Change</th>
<th>Div Yield (%)</th>
</tr>
</tfoot>
<tbody>
<tr th:each="stock : ${stocks}">
<td th:text="${stock.getSymbol()}"></td>
<td>
<form action="#" th:action="#{/banking/stocks/} + ${stock.symbol}" method="get">
<button class="btn btn-outline-success my-2 my-sm-0" th:id="'table_entry_childs_button_' + ${stock.symbol}" type="submit">
<i>Trade</i>
</button>
</form>
</td>
<td th:text="${stock.getName()}"></td>
<td th:text="${stock.getQuote().getPrice()}"></td>
<td th:class="${stock.getQuote().getChangeInPercent() > 0 ? 'text-success' : 'text-danger'}" th:text="${stock.getQuote().getChangeInPercent() + '%'} "></td>
<td th:if="${stock.getDividend().getAnnualYield() != null}" th:text="${stock.getDividend().getAnnualYield() + '%'}">0.00%</td>
<td th:if="${stock.getDividend().getAnnualYield() == null}" >0.00%</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</main>
You can exploit STOMP protocol and web sockets using spring boot.
For reference:
https://www.baeldung.com/spring-websockets-send-message-to-user
on back end side you can use
#Autowired
SimpMessagingTemplate messagetemplate;
public void somemethod(String strParam){
while (true){
// build string or json whatever you need to send
messagetemplate.convertAndSend("/blabla/blabla",strParam);
Thread.sleep(30*1000);
}
}
on front end side you have to use stomp.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js">
<script type="text/javascript">
function load(){
var stompClient = Stomp.client("ws://localhost:8080/ws");
stompClient.connect({}, function (frame) {
stompClient.subscribe('/blabla/blabla', function (message) {
// do something here
});
});
}
lastly, part of html where you want to call on load
<html>
<body onload="load()">
</body>
</html>
You can create an #Scheduled method that can call this API request every 30 seconds to get data and update your Front-End.
#Scheduled(fixedRate = 30000)
public void updateStocksElement() {
//Call your /banking/stocks rest endpoint
}
https://spring.io/guides/gs/scheduling-tasks/
In my jsp page there have a table with nested list value, i want to send that table value to the container, The outer table value were sent but the inner table value not sent to the container, I am new here please let me know how to over come this situation,
My jsp
<script>
function rowAdded(rowElement) {
//clear the imput fields for the row
$(rowElement).find("input").val('');
//may want to reset <select> options etc
//in fact you may want to submit the form
saveNeeded();
}
function rowRemoved(rowElement) {
saveNeeded();
}
function saveNeeded() {
$('#submit').css('color','red');
$('#submit').css('font-weight','bold');
if( $('#submit').val().indexOf('!') != 0 ) {
$('#submit').val( '!' + $('#submit').val() );
}
}
function beforeSubmit() {
alert('script Working');
return true;
}
$(document).ready( function() {
var config = {
rowClass : 'rule',
addRowId : 'addRule',
removeRowClass : 'removeRule',
formId : 'ruleListForm',
rowContainerId : 'ruleListContainer',
indexedPropertyName : 'ruleList',
indexedPropertyMemberNames : 'id,ruleName,parameterName,overwriteValue',
rowAddedListener : rowAdded,
rowRemovedListener : rowRemoved,
beforeSubmit : beforeSubmit
};
new DynamicListHelper(config);
});
</script>
<html>
<form:form action="/update" method="post" id="ruleListForm" modelAttribute="ruleListContainer">
<table border="1">
<thead>
<h3 align="center">Selected Rule</h3>
<tr>
<th data-field="id" width="25">ID </th>
<th data-field="details" width="20">RuleName </th>
<th data-field="parameter" width="240">Parameter </th>
</tr>
</thead>
<tbody id="ruleListContainer">
<c:forEach items="${List2}" var="as">
<tr class="rule">
<td><input type="hidden" name="ruleList[].id" value="${as.rule.id}" /> ${as.rule.id}</td>
<td><input type="hidden" name="ruleList[].ruleName" value="${as.rule.ruleName}" /> ${as.rule.ruleName}</td>
<td> <input id="one" class="datepicker" type="text" name="ruleList[].startDate" size="11" height="0.10"></td>
<td> <input id="two" class="datepicker" type="text" name="ruleList[].endDate" size="11" height="0.10"></td>
<td>
<table border="1">
<c:forEach items="${as.ruleAssignmentParameter}" var="asss">
<tr>
<td><input type="hidden" name="ruleList[].parameterName"value="${asss.parameterName}" > ${asss.parameterName}</td>
<td><input type="hidden" name="ruleList[].overwriteValue" value="${asss.overwriteValue}" /> ${asss.overwriteValue}</td>
</tr>
</c:forEach>
</table>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<br>
<input type="submit" value="Update">
</form:form>
</html>
Here is my model class
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import com.demo.app.model.RuleAssignmentParameter;
public class RuleAssUI {
private int id;
private String ruleName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRuleName() {
return ruleName;
}
public void setRuleName(String ruleName) {
this.ruleName = ruleName;
}
private List<RuleAssignmentParameter> ruleAssignmentParameter = new LinkedList<RuleAssignmentParameter>();
public List<RuleAssignmentParameter> getRuleAssignmentParameter() {
return ruleAssignmentParameter;
}
public void setRuleAssignmentParameter(List<RuleAssignmentParameter> ruleAssignmentParameter) {
this.ruleAssignmentParameter = ruleAssignmentParameter;
}
public RuleAssUI(){
}
public RuleAssUI(int id,String ruleName){
this.id=id;
this.ruleName=ruleName;
}
}
My container where i store the list value
import java.util.LinkedList;
import java.util.List;
public class RuleListContainer {
private List<RuleAssUI> ruleList = new LinkedList<RuleAssUI>();
public RuleListContainer() {
}
public RuleListContainer(List<RuleAssUI> ruleList) {
this.ruleList = ruleList;
}
public List<RuleAssUI> getRuleList() {
return ruleList;
}
public void setRuleList(List<RuleAssUI> ruleList) {
this.ruleList = ruleList;
}
Controller
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String update(#ModelAttribute("SpringWeb") RuleListContainer ruleListContainer, HttpSession session, ModelMap model) {
ruleListContainer.getRuleList().size();
for (RuleAssUI rul1 : ruleListContainer.getRuleList()) {
System.out.println("Id: " + rul1.getId());
System.out.println("RuleName: " + rul1.getRuleName());
for (RuleAssignmentParameter rul2 : rul1.getRuleAssignmentParameter()) {
System.out.println("ParameterName: " + rul2.getParameterName());
System.out.println("ParameterValue: " + rul2.getOverwriteValue());
}
}
session.setAttribute("ruleListContainer", ruleListContainer);
return "hello";
}
I am trying so many time but unable to fixed the issue, And browse also but did't get any proper help, so please help to do items
I NEED HELP PLEASE SOME BODY HELP ME...!
Thank you in advance
I think the problem is in your jsp file.
You need to set the index of each list element.
<c:forEach items="${List2}" var="as" varStatus="vs">
<tr class="rule">
<td><input type="hidden" name="ruleList[${vs.index}].id" value="${as.rule.id}" /> ${as.rule.id}</td>
<td><input type="hidden" name="ruleList[${vs.index}].ruleName" value="${as.rule.ruleName}" /> ${as.rule.ruleName}</td>
<td> <input id="one" class="datepicker" type="text" name="ruleList[${vs.index}].startDate" size="11" height="0.10"></td>
<td> <input id="two" class="datepicker" type="text" name="ruleList[${vs.index}].endDate" size="11" height="0.10"></td>
<td>
<table border="1">
<c:forEach items="${as.ruleAssignmentParameter}" var="asss" varStatus="assignments">
<tr>
<td><input type="hidden" name="ruleList[${vs.index}].ruleAssignmentParameter[${assignments.index}].parameterName" value="${asss.parameterName}" > ${asss.parameterName}</td>
<td><input type="hidden" name="ruleList[${vs.index}].ruleAssignmentParameter[${assignments.index}].overwriteValue" value="${asss.overwriteValue}" /> ${asss.overwriteValue}</td>
</tr>
</c:forEach>
</table>
</td>
</tr>
</c:forEach>
Also in your controller (POST method) you are trying to get the object identified by "SpringWeb" but should be "ruleListContainer", same name you have in your form tag
The problem was you had a list into RuleAssUI and you was not accesing correctly, you need 2 loops and indexes, one for each list.
Here is the key:
ruleList[${vs.index}].ruleAssignmentParameter[${assignments.index}].parameterName
I have a restaurant edit page located "/restaurant/edit/{id}". From that page I can (among other things) add tables to the restaurant by pressing an "Add tables" button. That button takes me to another page located "/restaurant/edit/{id}/table". The question is, after I have added the table - how do I get back to the previous page by pressing a button? Right now my contoller is returning "editRestaurant.jsp" which is the right value, but I don't know how to pass that same restaurant id as well. I hope you understand what I mean.
My RestaurantTableController.java:
#Controller
public class RestaurantTableController {
#Autowired
private RestaurantService restaurantService;
#Autowired
private RestaurantTableService restaurantTableService;
#RequestMapping(value="restaurant/{id}/table", method = RequestMethod.GET)
public String addRestaurantTable(Model model, #PathVariable Long id) {
model.addAttribute("table", new RestaurantTable());
return "newTable";
}
#RequestMapping(value = "restaurant/{id}/table", method = RequestMethod.POST)
public String addRestaurantTableAction(#PathVariable Long id, #ModelAttribute ("table") RestaurantTable table, BindingResult result) {
RestaurantTableFormValidator restaurantTableFormValidator = new RestaurantTableFormValidator();
restaurantTableFormValidator.validate(table, result);
if (result.hasErrors()) {
return "newTable";
}
restaurantService.mergeRestaurant(id, table);
return "editRestaurant";
}
}
My "newTable.jsp":
<body>
<jsp:include page="../fragments/menu.jsp"/>
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Add New Table</h2>
<form:form method="POST" modelAttribute="table">
<table>
<tr>
<td>Table size:</td>
<td><form:input path="tableSize" /></td>
<td><form:errors path="tableSize" cssClass="error"/></td>
</tr>
<tr>
<td>Table number:</td>
<td><form:input path="tableNumber" /></td>
<td><form:errors path="tableNumber" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" onclick="goback()"/>
</td>
</tr>
</table>
</form:form>
</section>
</div>
<jsp:include page="../fragments/footer.jsp"/>
</body>
Relevant methods in RestaurantController.java:
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
model.addAttribute("restaurant", restaurant);
return "editRestaurant";
}
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.POST, params="submit")
public String editRestaurant(#ModelAttribute ("restaurant") Restaurant restaurant, BindingResult result) {
RestaurantFormValidator restaurantFormValidator = new RestaurantFormValidator();
restaurantFormValidator.validate(restaurant, result);
if (result.hasErrors()) {
return "editRestaurant";
}
restaurantService.updateRestaurant(restaurant);
return "redirect:/bookings";
}
"editRestaurant.jsp":
<div id="body">
<section class="content-wrapper main-content clear-fix">
<h2>Edit</h2>
<form:form method="POST" modelAttribute="restaurant" >
<table>
<tr>
<td>Restaurant:</td>
<td><form:input path="restaurantName" /></td>
<td><form:errors path="restaurantName" cssClass="error"/></td>
</tr>
<tr>
<td>Address:</td>
<td><form:input path="address" /></td>
<td><form:errors path="address" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Submit" name="submit"/>
</td>
</tr>
<tr>
<c:forEach items="${restaurant.table}" var="item">
<td>${item.toString()}</td>
</c:forEach>
</tr>
<tr>
<td>Add Table</td>
</tr>
</table>
</form:form>
<div>
Back to List
</div>
</section>
</div>
After successful POST you should do a redirect.
Something like this:
return "redirect:/restaurant/edit/" + restaurant.getId();
or
return new RedirectView("/restaurant/edit/" + restaurant.getId(), false);
There is a different method you can use to return the model that will include the parameter. I believe this may solve your problem.
#RequestMapping(value = "restaurant/edit/{id}", method = RequestMethod.GET)
public String editRestaurant(#PathVariable Long id, Model model) {
Restaurant restaurant = restaurantService.getRestaurant(id);
return new ModelAndView("editRestaurant", "restaurant", restaurant);
}
In my program, I am generating dynamic form names based on the number of feedbacks I get. I am then taking the satisfaction, comment and feedbackId inputs. They are different for each iteration. This is giving me an IllegalStateException error.
My HTML form is:
<form action="#" th:action="#{/heart2heart/token/__${tokenId}__/}" method="post">
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover table-condensed">
<tr>
<th style="display:none;"></th>
<th th:text="#{service.desc}">Service</th>
<th th:text="#{feedback.description}">Feedback</th>
<th th:text="#{visit.date}">Date of Visit</th>
<th th:text="#{repr.name}">FU Repr</th>
<th th:text="#{resolution.response}">Response</th>
<th th:text="#{resolution.satisfactionLevel}">Satisfaction</th>
<th th:text="#{resolution.comment}">Comment</th>
</tr>
<tr th:each="feedback, feedbackStat : *{feedbacks}">
<td style="display:none;"><input type="hidden" th:field="*{feedbacks[__${feedbackStat.index}__].feedbackId}" th:value="${feedback.id}" /></td>
<td th:text="${feedback.service.description}">Steel</td>
<td th:text="${feedback.description}">Problem</td>
<td th:text="${feedback.visits[0].date}">12/08/2015</td>
<td th:text="${feedback.visits[0].repr.fullName}">XYZ</td>
<td th:text="${feedback.receipt.resolutions[0].response}">response</td>
<td>
<div class="radio">
<label><input type="radio" th:field="*{feedbacks[__${feedbackStat.index}__].satisfaction}" th:text="#{global.yes}" value="SATISFIED">Yes</input></label>
</div>
<div class="radio">
<label><input type="radio" th:field="*{feedbacks[__${feedbackStat.index}__].satisfaction}" th:text="#{global.no}" value="NOT SATISFIED">No</input></label>
</div>
</td>
<td><textarea th:field="*{feedbacks[__${feedbackStat.index}__].comment}" class="form-control" rows="2"></textarea></td>
</tr>
</table>
<div class="form-group">
<button type="submit" name="addRow" th:text="#{button.submit}"
class="btn btn-primary btn-md">Submit</button>
</div>
</div>
</form>
My controller is:
#RequestMapping(value = "/{tokenId}/", method = RequestMethod.POST)
public String addSatisfaction(#PathVariable int tokenId, #Valid ReceiptForm receiptForm, BindingResult result, Model model) {
try {
for (SatisfactionForm satisfactionForm : receiptForm.getFeedbacks()) {
Feedback feedback = new Feedback();
feedback.setId(satisfactionForm.getFeedbackId());
Feedback feedback1 = heart2heartService.getFeedbackById(feedback);
Resolution resolution = new Resolution();
resolution.setId(feedback1.getReceipt().getResolutions().get(0).getId());
resolution.setSatisfactionLevel(satisfactionForm.getSatisfaction().name());
resolution.setComment(satisfactionForm.getComment());
heart2heartService.addSatisfaction(resolution);
model.addAttribute("success", "Satisfaction added for tokenId " + tokenId);
}
} catch (Exception e) {
logger.error("Exception :: ", e);
}
return "success2";
}
#RequestMapping(value = "/{tokenId}/", method = RequestMethod.GET)
public String getSatisfaction(#PathVariable int tokenId, Model model) {
Token token = new Token();
token.setId(tokenId);
try {
model.addAttribute("feedbacks", heart2heartService.getFeedbacksByToken(token));
} catch (Exception e) {
logger.error("Exception :: ", e);
}
return "heart2heart/closeFeedback";
}
My forms are:
public class ReceiptForm {
private List<SatisfactionForm> feedbacks = new ArrayList<SatisfactionForm>();
public List<SatisfactionForm> getFeedbacks() {
return feedbacks;
}
public void setFeedbacks(List<SatisfactionForm> feedbacks) {
this.feedbacks = feedbacks;
}
}
and
public class SatisfactionForm {
public static enum Satisfaction {
NOT_SATISFIED, SATISFIED
}
private String comment;
private int feedbackId;
private Satisfaction satisfaction;
public String getComment() {
return comment;
}
public int getFeedbackId() {
return feedbackId;
}
public Satisfaction getSatisfaction() {
return satisfaction;
}
public void setComment(String comment) {
this.comment = comment;
}
public void setFeedbackId(int feedbackId) {
this.feedbackId = feedbackId;
}
public void setSatisfaction(Satisfaction satisfaction) {
this.satisfaction = satisfaction;
}
}
I am getting the following error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'feedbacks[0]' available as request attribute
How do I fix this?
You did not specify the form-backing bean in your Thymeleaf template.
You are using the *{} operator to access fields of the bean, but Thymeleaf does not know
which bean you want to use. To resolve the error, add a th:object to your form.
Assuming that heart2heartService.getFeedbacksByToken(token) returns a ReceiptForm your form would look like this:
<form action="#" th:action="#{/heart2heart/token/__${tokenId}__/}" method="post" th:object="${feedbacks}">
I have got a html page (with Thymeleaf):
<form action="#" th:action="#{/changeme}">
<fieldset>
<table style="width: 500px">
<tr th:each="esfield : ${esfields}">
<td>
<div>
<div class="checkbox">
<input type="checkbox" name="optionsMulti"
th:text="${esfield}" />
</div>
</div>
</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>
<button type="submit"
class="btn btn-xs btn-primary margin10-right paddingNew"
name="save">Calculate!</button>
</td>
<td></td>
</tr>
</table>
</fieldset>
</form>
When I click Calculate! it goes to my controller
#RequestMapping(value = "/changeme", params = { "save" })
public String save(final ModelMap m) {
m.addAttribute("centers", /*params*/);
return "clustering";
}
I would like to get information about checked boxes in my controller?
How can I do that?
Thank you in advance
You have basically two options :
either you use a different name for each checkbox
or you use spring tag <form:checkbox> instead of native <checkbox>
If you don't posted data will not allow you to know exactly what boxes were actually checked (excepted in cases all and none)
With the approach, you should use in your controller a #ModelAttribute annotated object containing a List<Boolean> and spring will automagically populate it with the values of your checkboxes.
#RequestMapping(value = "/changeme", params = { "save" })
public String save(#ModelAttribute BoxesForm form, final ModelMap m) {
// do what you need with form.getCheckboxes() ...
m.addAttribute("centers", /*params*/);
return "clustering";
}
public class BoxesForm {
List<Boolean> checkboxes;
// getter and setter omitted ...
}