Binding list to checkbox in spring - java

I have Offer entity class :
#Entity
public class Offer {
public Offer(){}
private int offerId;
private String offerBanner;
private String offerLongDesc;
private int offerLikeCount ;
List<Category> categoryList ;
#DateTimeFormat(pattern= "dd/MM/yyyy")
private Date offerStartDate;
<----all getters and setters---->
}
And a Category entity class
#Entity
public class Category{
public Category() {}
private int categoryId;
private int categoryParentId;
private String categoryName;
private Date categoryCreationDate;
<--getters n setters--->
}
In my offerDetails form i am trying to bind the categoryList (attribute Offer entity) to checkbox
offerEntry.jsp
<form:form class="form-horizontal" action="/addOffer" commandName="offerDetails" method="post" enctype="multipart/form-data" style=" margin-top:20px; padding-right:50px; padding-left:10px; ">
<div class="checkbox-list">
<c:forEach var="category" varStatus="categoryStatus" items="${categoriesList}">
<form:checkbox path="categoryList" value="${category.categoryId}"/> <c:out value="${category.categoryName}" /><br>
</c:forEach>
</div>
<-----Other div elements------>
</form:form>
I have Offer entity class :
#Entity
public class Offer {
public Offer(){}
private int offerId;
private String offerBanner;
private String offerLongDesc;
private int offerLikeCount ;
List<Category> categoryList ;
#DateTimeFormat(pattern= "dd/MM/yyyy")
private Date offerStartDate;
<----all getters and setters---->
}
And a Category entity class
#Entity
public class Category{
public Category() {}
private int categoryId;
private int categoryParentId;
private String categoryName;
private Date categoryCreationDate;
<--getters n setters--->
}
In my offerDetails form i am trying to bind the categoryList (attribute Offer entity) to checkbox
offerEntry.jsp
<form:form class="form-horizontal" action="/addOffer" commandName="offerDetails" method="post" enctype="multipart/form-data" style=" margin-top:20px; padding-right:50px; padding-left:10px; ">
<div class="checkbox-list">
<c:forEach var="category" varStatus="categoryStatus" items="${categoriesList}">
<form:checkbox path="categoryList" value="${category.categoryId}"/> <c:out value="${category.categoryName}" /><br>
</c:forEach>
</div>
<-----Other div elements------>
</form:form>
and here is my controller :
#RequestMapping(value = {"/addOffer"}, method = RequestMethod.GET)
public ModelAndView offerForm() {
ModelAndView mv = new ModelAndView("offerEntry");
Offer offer = new Offer();
try{
List<Category> categoryList=categoryRepository.getAllCategories();
mv.addObject("categoriesList",categoryList);
}catch(Exception e)
{
}
mv.addObject("offerDetails",offer);
return mv;
}
Converter class :
public class CategoryIdtoCategory implements Converter<String, Category>
{
#Inject
private CategoryRepository categoryRepo;
#Override
public Category convert(String categoryId)
{
try{
int categoryIdI = Integer.parseInt(categoryId);
return categoryRepo.findCategoryById(categoryIdI);
}catch (Exception e){
e.printStackTrace();
return null;
}
}
On Submit i want selected checkbox values to populate offerDetails.categoryList collection.
I have registered converter as well (for converting those category Ids to categoryObjects)
Bean registration:
<beans:bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" >
<beans:property name="converters">
<beans:list>
<beans:bean class="com.service.util.CategoryIdtoCategory"/>
</beans:list>
</beans:property>
</beans:bean>
I am still getting following error :
[Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'categoryList'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.domain.Category] for property 'categoryList[0]': no matching editors or conversion strategy found]
I am new to Spring . Please Excuse me if its a silly question.
Your help would be appreciated . :)

In the JSP change path to reference the category
In category entity override equal and hash methods
In converter convert result of toString method in the Category entity to a Category object.

You can solve with #InitBinder in your controller like :
#InitBinder
protected void initBinder(WebDataBinder binder) throws Exception{
binder.registerCustomEditor(Set.class,"categoryList", new CustomCollectionEditor(Set.class){
protected Object convertElement(Object element){
if (element instanceof String) {
Category category = categoryCache.get(Integer.parseInt(element.toString()));
return role;
}
return null;
}
});
}

Related

How can i retrieve the values from weak entity in spring using hibernate?

POJO class
public class Professor {
private long id;
private String department;
String imagepath;
private List<String> subjects;
public List<String> getSubjects() {
return subjects;
}
public void setSubjects(List<String> subjects) {
this.subjects = subjects;
}
}
Controller
List<Professor> list= pdao.getProfessorById(id);
for(Professor p : list){
String courses = String.join(",", p.getSubjects());
out.println(courses);
}
mv=new ModelAndView("profdetails","professors",list);
JSP
<c:forEach var="professor" items="${professors}">
<c:out value="${professor.getId()}" />
<c:out value="${professor.getFirstName()}" />
<c:out value="${professor.getLastName()}" />
<c:out value="${professor.getSubjects()}" />
</c:forEach>
I need to display subjects List of a professor on a JSP page.
My professor class has 'subjects' as a weak entity defined in hbm.xml file. Iam getting LAzyInitializationException

How can I collect object using thymeleaf?

PROBLEM:When I submitted the form, the server report:"Failed to convert property value of type java.lang.String[] to required type java.util.List for property ingredients".
MY GUESS:I think the problem is that collected property ingredients is String.
I use thymeleaf as frontend.
QUESTION:How can I collect ingredients using thymeleaf?
DOMAIN Taco:
private String name;
private List<Ingredient> ingredients;
DOMAIN Ingredient:
private final String id;
private final String name;
private final Type type;
public static enum Type{
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
}
CONTROLLER:
import taco.Ingredient.Type;
//method to show design
public String showDesign(Model model) {
List<Ingredient> ingredients = new ArrayList<>();
ingredientRepo.findAll().forEach(i-> ingredients.add(i));
Type[] types = Type.values();
for(Type type:types) {
model.addAttribute(type.toString().toLowerCase(),filterByType(ingr
edients, type));
}
model.addAttribute("taco", new Taco());
return "design";
}
//method that is used to handle the post request
#PostMapping
public String processDesignForm(Taco taco) {
log.info("process taco: "+taco);
return "redirect:/orders/current";
}
DESIGN(use thymeleaf):
<form method="POST" th:object="${taco}">
<div th:each="ingredient : ${wrap}">
<input name="ingredients" type="checkbox"
th:value="${ingredient.id}" />
</div>
</form>
You can do the following, get the ids selected (ingredients) as RequestParam
#PostMapping
public String processDesignForm(Taco taco, #RequestParam("ingredients") List<String> idIngredients) {
log.info("process taco: "+taco);
if(idIngredients != null){
for(String id : idIngredients){
...//handle it
}
}
...

Spring MVC: The request sent by the client was syntactically incorrect when creating a new entity record

Good afternoon,
I am newbie to Spring MVC. I'm stuck with the following error while running my project "The request sent by the client was syntactically incorrect."
My project has two entities, Team and Country which have a ManyToOne relationship. Both these entities map tables created in mysql database.
I started the project with only the Team entity, and sucessfuly created my classes (DAO, controller, services, etc) and jsp to create new teams.
Now, I created the class Country to relate both entities and I added a dropdown list in the "add-team-form.jsp" to select the country of the new team. This page is correctly displayed (all countries appear in the dropdown list), however, when I click "submit" to create the new team, I get the error "The request sent by the client was syntactically incorrect."
Can you please help me to identify my error? I'm guessing it's in the "add-team-form.jsp".
1 - Entity Team:
#Entity
#Table(name="teams")
public class Team implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name", length = 40, nullable = false)
private String name;
#Column(name = "rating", length = 6, nullable = false)
private Integer rating;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_country", nullable = false)
private Country country;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getRating() {
return rating;
}
public void setRating(Integer rating) {
this.rating = rating;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
}
2 - Entity Country:
#Entity
#Table(name = "countries")
public class Country implements Serializable{
#Id
#Column(name= "id_country", length = 6)
private String idCountry;
#Column(name = "name", length = 255, nullable = false)
private String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "country")
private List<Team> teams;
public String getIdCountry() {
return idCountry;
}
public void setIdCountry(String idCountry) {
this.idCountry = idCountry;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My Team DAO
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public void addTeam(Team team) {
getCurrentSession().save(team);
}
}
My Team Service
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
#Autowired
private TeamDAO teamDAO;
public void addTeam(Team team) {
teamDAO.addTeam(team);
}
My Team Controller
#Controller
#RequestMapping(value="/team")
public class TeamController {
#Autowired
private TeamService teamService;
#Autowired
private FilterService filterService;
#RequestMapping(value="/add", method=RequestMethod.GET)
public ModelAndView addTeamPage() {
ModelAndView modelAndView = new ModelAndView("add-team-form");
modelAndView.addObject("team", new Team());
return modelAndView;
}
#RequestMapping(value="/add", method=RequestMethod.POST)
public ModelAndView addingTeam(#ModelAttribute Team team) {
ModelAndView modelAndView = new ModelAndView("home");
teamService.addTeam(team);
String message = "Team was successfully added.";
modelAndView.addObject("message", message);
return modelAndView;
}
#ModelAttribute("countryList")
public Map<String, String> getCountryList(){
Map<String, String> countryList = filterService.getCountries();
return countryList;
}
...
}
My "add-team-form.jsp"
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Add team page</title>
</head>
<body>
<h1>Add team page</h1>
<form:form method="POST"
modelAttribute="team"
action="${pageContext.request.contextPath}/team/add.html">
<table>
<tbody>
<tr>
<td>Name:</td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td>Rating:</td>
<td><form:input path="rating" /></td>
</tr>
<tr>
<td><label>Country</label></td>
<td>
<form:select path="country.idCountry">
<form:options items="${countryList}" />
</form:select>
</td>
<tr>
<td><input type="submit" value="Add" /></td>
<td></td>
</tr>
</tbody>
</table>
</form:form>
</body>
</html>
There is no error showing in the console of eclipse, but here is the error im receiving from the browser:
HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect.
Apache Tomcat/7.0.47
There's a couple of problems I can see here - you are posting to add/team/add.html and not hitting your post handler. You don't need the action attribute as you're posting to the same endpoint;
<form:form method="POST" modelAttribute="team" >
Secondly your are injecting the countries as a map, so these are ID/display values which works great for key/value pairs and for binding a value to a string field. In this case, Spring is trying to bind your country ID (String) to the team.country(Country) field which will fail. To help Spring out you need a databinder; in your controller add;
#InitBinder
public void initBinder (WebDataBinder binder) {
binder.registerCustomEditor(Country.class, new CountryEditor());
}
and create the property editor class;
public class CountryEditor extends PropertyEditorSupport {
#Override
public void setValue(Object value) {
super.setValue(value);
}
public String getAsText() {
if (getValue() == null) return null;
return ((Country) getValue()).getName();
};
public void setAsText(String text) throws IllegalArgumentException {
if (text != null) {
Country country = // something like filterService.getCountryById(text);
setValue(country);
}
};
}
There's more information in the Spring documentation
The error you are receiving generally happens if a parameter is missing or is in a different format and cannot be converted to the expected type.Check the values being passed to the Team object.You can either log the request and response or set the log level to "DEBUG",this will display the exact error in logs.

How to return the value of a JSP select box in Spring MVC?

I'm sending to my JSP a Map<String entityDescription, Entity entity> to populate a <form:select> that's defined as:
<form:form id="form" modelAttribute="pojo" action="create" method="post">
<div>
<label for="ftpConnection">FTP Connection: </label>
<form:select path="ftpConnection">
<form:options items="${ftpList}" itemLabel="description" />
</form:select>
</div>
</form:form>
The DTO has the FTPConnection ftpConnection field that should receive the ftpConnection defined on the path property of the <form:select> element.
The POST method is, roughly, defined as:
#RequestMapping(value = "/parameter/create", method = RequestMethod.POST)
public String createPost(#ModelAttribute("pojo") ParameterPojo pojo, ModelMap model, Errors errors) throws IOException, Exception {
// validate entities
// save what has to be saved
return "where it has to go";
}
The FtpConnection bean for this instance is a very simple POJO, defined as:
#Entity
#Table(name = "ftp")
public class FtpConnection extends BasePojo {
#Column(name = "description")
private String description;
#Column(name = "url")
private String url;
#Column(name = "port")
private String port;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
// getters and setters
}
The DTO called ParameterPojo is another very simple POJO:
public static class ParameterPojo {
private String id;
private String description;
private String agentId;
private FtpConnection ftpConnection;
// getters and setters
}
The only output I get is at the browser, like the image bellow.
No console output.
How can I work this out?
well I had write a small poc for you this works for me.
the DTO are the same
I don't know if you developed the custom converter for the FtpConnection bean, I assumed of yess but if you don't implements this waas the cause of your 400 error becouse spring when you submit the form don't know as converter the bean in a way for submit the info for this propouse I developed such confverter:
public class FtpToStringConverter implements Converter<FtpConnection, String> {
#Override
public String convert(FtpConnection ftpConnection) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(ftpConnection);
} catch (IOException e) {
return "{}";
}
}
}
public class StringToFtpConverter implements Converter<String, FtpConnection> {
#Override
public FtpConnection convert(String s) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(new StringReader(s),FtpConnection.class);
} catch (IOException e) {
return null;
}
}
}
then I register the custom converter in this way
#Component
public class MyDefaultConversionService extends DefaultConversionService {
#Override
public void addConverter(Converter<?, ?> converter) {
super.addConverter(converter);
super.addConverter(new StringToFtpConverter());
super.addConverter(new FtpToStringConverter());
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.springapp.mvc"/>
<mvc:annotation-driven conversion-service="myDefaultConversionService"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
then I implemented a simpel controller like this
#Controller
public class HelloController {
#RequestMapping(value = {"/index"}, method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Hello world!");
List<FtpConnection> ftpConnections = new ArrayList<FtpConnection>();
FtpConnection ftpConnection = new FtpConnection();
ftpConnection.setUrl("url1");
ftpConnection.setPort("22");
ftpConnection.setUsername("user1");
ftpConnection.setPassword("pass1");
ftpConnection.setDescription("desc1");
ftpConnections.add(ftpConnection);
ftpConnection = new FtpConnection();
ftpConnection.setUrl("url1");
ftpConnection.setPort("21");
ftpConnection.setUsername("user2");
ftpConnection.setPassword("pass2");
ftpConnection.setDescription("desc2");
ftpConnections.add(ftpConnection);
model.addAttribute("ftpList", ftpConnections);
model.addAttribute("pojo",new ParamiterPojo());
return "hello";
}
#RequestMapping(value = "/paramiter/create" , method = RequestMethod.POST)
public String post(#ModelAttribute("pojo") ParamiterPojo paramiterPojo, ModelMap modelMap, Errors errors){
System.out.println(paramiterPojo);
return "hello";
}
}
this is the my hello.jsp
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<body>
<h1>${message}</h1>
<form:form modelAttribute="pojo" method="post" action="paramiter/create">
<div>
<form:select path="ftpConnection">
<form:options items="${ftpList}" itemLabel="description" />
</form:select>
</div>
<button> Submit</button>
</form:form>
</body>
</html>
Of course this is a very simpel sampel and you consider this as a poc.
resuming the problem that I find in your code was:
the absence of converter
the wrong action in the jsp
I hope that this quite detailed description of my solution was fine grained enough.
Change your form to include pojo if you want to use the annotations like you state.
<form:form commandName="pojo" action="" methon="post">
<form:options items="${ftpList}" itemLabel="description" />
</form:form>
Since that your controller react to the post at parameter/create url in your <form:form> .... </form:form> section the action attribute should be parameter/create and not create

error HTTP Status 400 -The request sent by the client was syntactically incorrect. updated

First of all I have two tables job, category which are in diagram as
and my entities are :
#Entity
#Table( name = TableName.JOB_TABLE)
public class Job {
#Id
#GeneratedValue
private Integer id;
private String title;
private String description;
#OneToMany(mappedBy = "job")
private List<Category> categories;
// omitting setters an getters for brevity
}
and
#Entity
#Table( name = TableName.CATEGORY_TABLE)
public class Category {
#Id
#GeneratedValue
private Integer id;
private String name;
#ManyToOne
#JoinColumn(name = "job_id")
private Job job;
// omitting setters an getters for brevity
}
JobService is
#Service
public class JobService implements IDatabaseCrud<Job>{
#Autowired
private JobRepository jobRepository;
#Autowired
private CategoryRepository categoryRepository;
public void saveCategory(Job job) {
List<Category> categories = job.getCategories();
for (Category category : categories) {
category.setJob(job);
categoryRepository.save(category);
}
}
#Override
public void save(Job obj) {
// TODO Auto-generated method stub
jobRepository.save(obj);
saveCategory(obj);
}
}
now I don't have any idea to save new job where I've to save one Job with many categories selected from list.
<form:form commandName="job">
<form:input path="title"/><br>
<form:input path="company"/><br>
<form:input path="location"/><br>
<form:input path="url"/><br>
<form:input path="email"/><br>
<form:input path="description"/><br>
<form:select path="categories">
<form:options items="${categories}" itemValue="id" itemLabel="name"/>
</form:select><br>
<form:input path="createdAt"/><br>
<form:input path="toApply"/><br>
<input type="submit" value="Add Job">
</form:form>
the above form is not submitting data to controller and gives error HTTP Status 400 -The request sent by the client was syntactically incorrect. following controller I want to save these details to DB
#Controller
public class JobController {
private static final Logger logger = LoggerFactory.getLogger(JobController.class);
#Autowired
private JobService jobService;
#Autowired
private CategoryService categoryService;
#ModelAttribute("job")
public Job constructJob() {
return new Job();
}
#RequestMapping(value = "/jobs", method = RequestMethod.GET)
public String showJobs(Model model) {
model.addAttribute("jobs", jobService.findAll());
return "jobs";
}
#RequestMapping(value = "/jobs/{id}", method = RequestMethod.GET)
public String showJobDetail(Model model, #PathVariable Integer id) {
model.addAttribute("job", jobService.findJobWithCategories(id));
return "job-detail";
}
#RequestMapping(value = "/show-add-job", method = RequestMethod.GET)
public String showJobForm(Model model) {
model.addAttribute("categories", categoryService.findAll());
return "add-job";
}
#RequestMapping(value = "/show-add-job", method = RequestMethod.POST)
public String addJobDetail(#ModelAttribute("job") Job job) {
///jobService.save(job);
List<Category> categories = job.getCategories();
for (Category category : categories) {
logger.info("DEBUG job object", category);
}
return "redirect:/jobs";
}
}
with the above stuff I'm unable to save job with categories when I submit the form I get HTTP Status 400. is some thing wrong in form.
This is URL to that project.
The problem you are getting is related to how you bind the categories, in fact you need to help the framework resolve them, e.g. with a help of WebDataBinder. You should add something like
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Category.class,
new PropertyEditorSupport() {
#Override
public void setAsText(String text) {
// replace the dao with your appropriate repository call
Category category = dao.find(Category.class,
Integer.parseInt(text));
setValue(category);
}
});
}
about the createdAt
the trouble you're facing there is that you need to tell the framework in which format are you entering the date. For example, if you are passing the date in the format of yyyy\MM\dd, than it will simply work.
If you are using some other format it will suffice to annotate the property with #DateTimeFormat. A concrete example, you can annotate your property inside the Job class with
#DateTimeFormat(iso= DateTimeFormat.ISO.DATE)
#Column(name = "created_at")
private Date createdAt;
DateTimeFormat.ISO.DATE expects a date in yyyy-MM-dd format, or use a pattern attribute, and the format you prefer
Hello i checked out your code and found that you have three issues: one is related to submission of the date field - createdAt, the other one is with the applyTo field and the other one is with categories field.
About the problem with dates you should check documentation for spring #InitBinder. Here is a good SO thread for it. Basic problem is that spring don't know how to bind date to String.
Other problem with categories field is that you should implement a Converter that will convert categoryId which is a number to Category class. see here good thread.
if you remove all three fields - applyTo,createdAt and categories, your form submission will work. but if you want to work as expected please implement #initBinder for date and Converter for categories

Categories

Resources