Spring MVC checkboxes HTTP Status 400 The request sent by the client was syntactically incorrect - spring-mvc

I have this simple form with 2 checkboxes and a submit button. When I submit the form, I get this error
HTTP Status 400 The request sent by the client was syntactically incorrect.
This is my POJO:
public class Menu{
private String day;
private String name;
private int price;
public Menu(){
}
public Menu(String day, String name, int price) {
this.day = day;
this.name = name;
this.price = price;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDay() {
return day;
}
public void setDay(String l) {
this.day = l;
}
#Override
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.day.hashCode();
hash = 7 * hash + this.name.hashCode();
return hash;
}
#Override
public boolean equals(Object object) {
boolean result = false;
System.out.println("ARE YOU EVER CALLLED HOW MANY TIMES");
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Menu sc = (Menu) object;
if (this.day == sc.getDay() && this.name == sc.getName()
&& this.price == sc.getPrice()) {
result = true;
}
}
return result;
}
This is my Order class:
public class Order {
private List<Menu> menus = new ArrayList<Menu>();
public Order(){}
public Order(ArrayList<Menu> menus){
this.menus = menus;
}
public List<Menu> getMenus() {
return menus;
}
public void setMenus(ArrayList<Menu> menus) {
this.menus = menus;
}
}
And this is my controller:
#Controller
public class RestaurantController {
#RequestMapping(value = "/menu", method = RequestMethod.GET)
public String menuPage(Model model){
Order o = new Order();
ArrayList<Menu> m = new ArrayList<Menu>();
m.add(new Menu("Sunday", "Phir Aloo", 12));
m.add(new Menu("Sunday", "Phir Cholay", 9));
model.addAttribute("today", m);
model.addAttribute("order", o);
return "/menu";
}
#RequestMapping(value = "/confirm", method = RequestMethod.POST)
public String done(#ModelAttribute(value="order") Order order, Model model){
return "/confirm";
}
And this is my menu.jsp: (http://localhost:9080/res/menu)
<form:form modelAttribute="order" method="post" action="/res/confirm">
<c:forEach items="${today}" var="r">
<form:checkbox path="menus" value="${r}" label="${r.name } ${r.price }" />
</c:forEach>
<input type="submit" value="Submit Data">
</form:form>
Now I just expect Class Order's property 'menus' to be filled with selected checkboxes. Instead I get this error "The request sent by the client was syntactically incorrect. I have looked up every possible answer on this website but nothing seems to be solving the problem.
After #R Sawant's suggestion I was able to solve the problem. Here is my Property Editor.
public class MenuTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
setValue(new Menu(text.toUpperCase()));
}
}
I kept this class inside the same package which has Menu.java and Order.java
Now inside my controller wrote this:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Menu.class, new MenuTypeEditor());
}
And voila! Magic happened.
I hope this answer can help someone.

The problem is with the value you are posting when the check box is ticked. Look at the below code
<form:checkbox path="menus" **value="${r}"** label="${r.name } ${r.price }" />
See what have assigned to value attribute in the above line. Its whole object of menu. It will essentially post the toString() representation of the object. Since you have not implemented toString() for Menu class, something like Menu#1ed2e55e gets posted for the check box value. Spring is unable to convert this to something meaningful and hence the problem.
You have to make use of property editor support to deal with these type of situations. Property editor will help you convert string to Object and vice versa. In your case String to Menu object and vice versa. Take a look at examples of property editors. Hope this helps
Edit:- a google search got this result. Take a look at it, may help you to understand.

Related

List parameter on child component not updating

I have a child component for filtering a search (DropdownFilter) which takes an input of a list of suggestions and a function to update that list.
For some reason DropdownFilter.Suggestions isn't being updated after it is initially set and I don't know how to update it again. Any information about how to update the property after it is initially bound would be great!
DropdownFilter.razor:
<input id="search" #onfocus="SearchFocused" #onblur="SearchUnfocused" #oninput="UpdateSearchText" />
#foreach (var suggestion in Suggestions)
{
<p>#suggestion</p>
}
#code {
[Parameter]
public Action<string> SearchFieldChanged { get; set; }
//[Parameter]
//public RenderFragment<TSuggestion> SuggestionTemplate { get; set; }
[Parameter]
public List<string> Suggestions { get; set; }
private bool searchFocus = false;
private void SearchFocused(FocusEventArgs args) {
searchFocus = true;
//UpdateSearchText();
}
private void SearchUnfocused(FocusEventArgs args) => searchFocus = false;
private void UpdateSearchText(ChangeEventArgs args)
{
SearchFieldChanged.Invoke((string)args.Value);
}
public void Refresh() {
StateHasChanged();
}
}
Index.razor:
#page "/example"
<div class="container-fluid dropdown-holder">
<DropdownFilter #ref="dropdown" Suggestions="#maskResults" SearchFieldChanged="UpdateSearchResults" />
</div>
#code {
DropdownFilter dropdown;
public class MaskResult {
public string name;
}
static readonly string[] allMasks = {
"Electric",
"Water",
"Ground",
"Fire",
"Bug"
};
public List<string> maskResults = allMasks.ToList();
private void UpdateSearchResults(string search)
{
search = search.ToLower();
maskResults = allMasks.Where((mask) =>
{
return mask.ToLower().StartsWith(search);
}).ToList();
dropdown.Refresh();
}
}
I think that you are trying to create a Datalist, please check this answer:"
datalist How to bind selected item to object
If you add a StateHasChanged() call just here it should work:
private void UpdateSearchResults(string search)
{
search = search.ToLower();
maskResults = allMasks.Where((mask) =>
{
return mask.ToLower().StartsWith(search);
}).ToList();
StateHasChanged(); // Add this line
dropdown.Refresh();
}
As I understand, if you update manually a Parameter of a component, there are some cases where Blazor does not get automatically the info that it needs to update its components. So if you call StateHasChanged, it will reevaluate all Parameters of the childreen of the component where you do the call.
I'll let someone correct me if I am wrong.
Thanks and good luck :)

RestController JSON Response object format

I am using Spring Boot to return data from a Repository. I would like to format my JSON so that it plays nicely with ExtJS' ajax handling. Essentially I would like to include properties to handle success/failure, count, and errorMsg along with a List of data from the repository.
I have tried by creating a ResponseDTO object that I'm returning from my Rest Controller.
#RestController
public class AdminController {
private static final Logger logger = LogManager.getLogger(AdminController.class);
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#GetMapping("/searchUsers")
public ResponseDTO searchUsers(String name, String active) {
int activeFlag;
List<User> users;
ResponseDTO resp;
if(active.equals("true")) {
activeFlag = 1;
} else activeFlag=0;
if(StringUtils.isEmpty(name)) {
users= userService.findAllUsers(activeFlag);
} else {
users= userService.findByUsernameActive(name, activeFlag);
}
return new ResponseDTO(users, true);
}
}
Here's my DTO that I use in the controller:
public class ResponseDTO {
private boolean success;
private int count = 0;
private List<?> values;
public boolean getSuccess() {
return this.success;
}
public void setState(boolean st) {
this.success=st;
}
public int getCount() {
return this.count;
}
public void setCount(int cnt) {
this.count=cnt;
}
public List<?>getValues() {
return this.values;
}
public void setValues(List<?> vals) {
this.values = vals;
}
public ResponseDTO(List<?> items, boolean state) {
this.success = state;
values = items;
this.count = items.size();
}
}
Here's what the JSON I get back looks like:
{
"ResponseDTO": {
"success":true,
"count":2,
"values":[{obj1 } , { obj2}]
}
}
what I would like to get is something more like:
{
"success" : true,
"count" : 2,
"values" [{obj1},{obj2}]
}
I'm using Spring Boot and Jackson annotations. I have used an annotation to ignore individual fields in the objects in the results array, but I can't find a way to unwrap the ResponseDTO object to not include the class name.
When you serialize ResponseDTO POJO, you should not get 'ResponseDTO' in the response by default. Because, the root wrap feature is disabled by default. See the doc here. If you have the below code, please remove it.
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);

Reflection issue: NoSuchMethodException <init> ...specification.SearchCriteria, [Ljava.lang.String;)

Well, NoSuchMethodException is normally well self-explaining. Unfortunately, in my case, I couldn't even guess why I am getting such error.
I am taking care a code from other developer and I must maintain it. It was designed with specification pattern in mind. In order to make the search engine very generic, basically, any string passed from client to rest service is split in order to build the search criteria.
When executing "clazzSpec.getDeclaredConstructor(SearchCriteria.class, String[].class).newInstance(param);" I get
java.lang.NoSuchMethodException: br.com.mycompany.specification.SomethingSpecification.<init>(br.com.mycompany.specification.SearchCriteria, [Ljava.lang.String;)
Looking the image bellow, I can't see what is missed
SearchCriteria:
public class SearchCriteria {
private String key;
private String operation;
private Object value;
public SearchCriteria(String key, String operation, Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
SomethingSpecification
public class SomethingSpecification extends Specification<Something> {
public SomethingSpecification(SearchCriteria criteria) {
super(criteria);
}
#Override
public Predicate toPredicate(Root<Something> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
switch (criteria.getOperation()) {
case "=":
...
}
return super.toPredicate(root, query, builder);
}
}
The reflection code looks for a constructor with two arguments: SearchCriteria and a String[]. But the only constructor for SomethingSpecification only has one argument.

PreSelect Value from Dropdown

I was able to populate my dropdown, however I cannot preselect the value of the dropdown base on the value coming from DB.
My Thymeleaf
<select id="inputstatus" name="status" th:field="*{status}" >
<option th:each="enumStatus : ${listStatus}"
th:value="${enumStatus.code}"
th:text="#{${enumStatus.value}}" />
</select>
My Controller:
#RequestMapping(value = "userdetails/{username}")
public String getAccounts(#PathVariable String username, Model model) {
Account accountDetail = rsAccountDetailsService.loadAccountByUserName(username);
model.addAttribute(ACCNTSEARCH_MODEL_ACCNTSTATUS_KEY, AccountDetailsStatus.values());
model.addAttribute("userdetailform",accountDetail);
return "account/userdetails";
}
My ENUM
public enum AccountDetailsStatus {
ACTIVE(0, "status.active"),
EXPIRED(2, "status.expired"),
LOCKED(3, "status.locked");
private int code;
private String value;
private final static class BootstrapSingleton {
public static final Map<String, AccountDetailsStatus> lookupByValue = new HashMap<String, AccountDetailsStatus>();
public static final Map<Integer, AccountDetailsStatus> lookupByCode = new HashMap<Integer, AccountDetailsStatus>();
}
AccountDetailsStatus(int code, String value) {
this.code = code;
this.value = value;
BootstrapSingleton.lookupByValue.put(value, this);
BootstrapSingleton.lookupByCode.put(new Integer(code), this);
}
public int getCode() {
return code;
}
public String getValue() {
return value;
}
}
If the user details were loaded with for example "ACTIVE" status, the active status in the dropdown is not selected.
I think your are looking for something similar use the th:selected tag
<option th:each="i : ${#numbers.sequence(0, 23)}" th:value="${i}" th:text="${i}" th:selected="${ i==9 } ">Options</option>
i linked some similar post here
http://forum.thymeleaf.org/th-selected-not-working-on-multiple-select-td4025883.html
th:selected a number in a select/option with Thymeleaf doesn't work

How to parse json data into different object dynamically by using Jackson in Spring3 MVC project

I want to know if there is a way to parse json data dynamically into different object by using jackson feature in Spring3.
I have a parent class as below:
public class Recording {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
And two children:
public class Child1Recording extends Recording {
private String program;
public String getProgram() {
return program;
}
public void setProgram(String program) {
this.program = program;
}
}
public class Child2Recording extends Recording {
private String time;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
Controller like this:
#RequestMapping(value = "/init/postCheck.ajax", method = RequestMethod.POST)
public #ResponseBody
String postCheck(#RequestBody Recording recording) {
if (recording instanceof Child2Recording) {
return "\"child2 success\"";
} else if (recording instanceof Child1ecording) {
return "\"child1 success\"";
}
return "\"only parent Recording\"";
}
i have different scenarios to post different json data to the backend, i am wondering if there is a way to make controller works like i said above?
For now, if i send a Child2Recording data, an error occurs when parsing it. I can't get the correct object that i expect.

Resources