Spring form validation on dependent object - java

I faced this problem while I was validating my forms, For single entities it worked fine. But when I try to validate a object with nested objects I get this error.
HTTP Status 500 - Request processing failed; nested exception is javax.validation.ConstraintViolationException: Validation failed for classes [com.poultry.jp.model.PaymentRequest] during persist time for groups [javax.validation.groups.Default, ]
Following is my controller
#RequestMapping(value = {"user/addMedicineOrder","admin/addMedicineOrder"}, method = RequestMethod.GET)
public String addMedicineOrderGET(#ModelAttribute("medicineOrder") MedicineOrder medicineOrder,Model model) {
List<SupplierReport> supplierReport = supplierService.getSupplierNames();
List<MedicineOrderReport> medicineOrderReport = medicineOrderService.getMedicineOrderDetails();
List<PaymentRequestReport> paymentRequestReport = paymentRequestSerivice.getPaymentRequestDates();
List<MedicineReport> medicineReport = medicineService.getMedicineDetails();
model.addAttribute("medicineOrderReport",medicineOrderReport);
model.addAttribute("supplierReport", supplierReport);
model.addAttribute("paymentRequestReport", paymentRequestReport);
model.addAttribute("medicineReport", medicineReport);
return "addMedicineOrder";
}
#RequestMapping(value = {"user/addMedicineOrder","admin/addMedicineOrder"}, method = RequestMethod.POST)
public String addMedicineOrderPOST(#Valid #ModelAttribute("medicineOrder") MedicineOrder medicineOrder,BindingResult result) {
if (result.hasErrors()) {
return "addMedicineOrder";
} else {
medicineOrderService.save(medicineOrder);
return "redirect:addMedicineOrder.html";
}
}
Following is my Medicine Order Model
public class MedicineOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long medicineOrderId;
#OneToMany(mappedBy = "medicineOrder", cascade = CascadeType.ALL,fetch = FetchType.EAGER,orphanRemoval=true)
private List<MedicineOrderDetails> medicineOrderDetails = new ArrayList<MedicineOrderDetails>();
#ManyToOne
private Supplier supplier;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Temporal(TemporalType.DATE)
private Date date;
private double total;
private double discount;
private boolean inStock;
#OneToOne(cascade={CascadeType.MERGE , CascadeType.PERSIST})
#JoinColumn(name="paymentRequest_id")
private PaymentRequest paymentRequest;
private boolean isDeleted;
private Date created;
private Date updated;
// Getters and Setters
}
Following is the dependent class Payment Request
public class PaymentRequest{
public static final String FIND_PAYMENT_REQUEST_DATES = "findPaymentReequestDates";
public static final String FIND_PAYMENT_REQUEST_BY_ID = "findPaymentReequestById";
public static final String FIND_PAYMENT_REQUEST_REPORT = "findPaymentRequestReport";
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long paymentId;
private double amount;
#Type(type = "text")
#NotEmpty
private String description;
private String chequeID;
private String status;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Temporal(TemporalType.DATE)
private Date date;
private boolean isDeleted;
private boolean isPaid;
private Date created;
private Date updated;
//Getters and Setters
}
and Following is where I persist Medicine Order which persist the payment request with it.
#Repository("MedicineOrderRepository")
public class MedicineOrderRepositoryImp implements MedicineOrderRepository{
#PersistenceContext
private EntityManager entityManager;
public MedicineOrder save(MedicineOrder medicineOrder){
for(MedicineOrderDetails order : medicineOrder.getMedicineOrderDetails())
{
order.setMedicineOrder(medicineOrder);
}
medicineOrder.getPaymentRequest().setStatus("Pending");
entityManager.persist(medicineOrder);
entityManager.flush();
return medicineOrder;
}
}
And Finally following the jsp code.
<div class=".col-md-6">
<form:form commandName="medicineOrder" class="form-horizontal"
autocomplete="off">
<form:errors path="*" Class="alert alert-danger" element="div" />
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Description</label>
<div class="col-sm-3">
<form:textarea path="paymentRequest.description" type="text"
class="form-control" id="inputDescription"
placeholder="Enter Short Description" rows="3" />
</div>
</div>
<div class="form-group">
<label for="inputAmount" class="col-sm-2 control-label">Amount</label>
<div class="col-sm-3">
<form:input path="paymentRequest.amount" type="text"
class="form-control" id="inputAmount" placeholder="Enter Amount" />
</div>
</div>
<div class="form-group">
<label for="supplierId" class="col-sm-2 control-label">Supplier</label>
<div class="col-sm-5">
<form:select path="supplier.supplierId" id="supplierId"
class="form-control">
<form:options items="${supplierReport}" itemLabel="name"
itemValue="supplierId" id="" />
</form:select>
</div>
</div>
<div class="form-group">
<label for="inputTotal" class="col-sm-2 control-label">Total</label>
<div class="col-sm-5">
<form:input path="total" type="text" class="form-control"
id="inputTotal" name="inputTotal" />
</div>
</div>
<div class="form-group">
<label for="inputDiscount" class="col-sm-2 control-label">Discount
</label>
<div class="col-sm-5">
<form:input path="discount" type="text" class="form-control"
id="inputDiscount" />
</div>
</div>
<input type="submit" value="Save Medicine Order"
class="btn btn-primary">
</form:form>
</div>

I was able to resolve this.
Credit goes to this forum, http://forum.spring.io/forum/spring-projects/web/87783-jsr-303-validation-on-child-objects
what I had to do was just add #Valid annotation in my parent class's child object
EX:
#Valid
private PaymentRequest paymentRequest;

Related

Thymeleaf and Springboot th:field Null

I got a MVC web page and i try to get a value from a input type="datetime-local" and save the value in th:field. to be able to save these dates and also work with them
But it seams to work only in input="text" tags, not type="datetime-local" because when i debug, the date value of the input that is type="datetime-local"
I need the client to select the Date the event its goint to start
Here is an example of the whole form and the two inputs that save the date.
Client view
[enter image description here][1]
View
<div class="container">
<div class="row">
<div class="col-md-4 mt-5">
<form th:action="#{/guardar/} + ${usuario.id_user}" method="post" th:object="${event}">
<div class="form-group">
<label for="title" >Titulo </label>
<input type="text" id="title" placeholder="Titulo" class="form-control" th:field="*{title}"/>
</div>
<div class="form-group">
<label for="e_description" >Descripción</label>
<input type='text' name="e_description" th:field="*{e_description}" placeholder="Descripcion" class="form-control"/>
</div>
<div class="form-group">
<label for="startDate">Inicio de Evento:</label>
<input type="text" id="time" placeholder="Inicio de Evento" class="form-control" th:field="*{startDate}"/>
</div>
<div class="form-group">
<label for="endDate">Termino de Evento:</label>
<div class="input-group date" id="endDate">
<input type="datetime-local" id="time2" placeholder="Termino de Evento" class="form-control" th:field="*{endDate}"/>
<div class="input-group-addon input-group-append">
<div class="input-group-text">
<i class="fa fa-clock-o"></i>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="className" >ClassName</label>
<input type="text" name="className" th:field="*{className}" placeholder="className" class="form-control"/>
</div>
<div class="form-group">
<label for="icon">Icono</label>
<input type="text" name="icon" th:field="*{icon}" placeholder="icon" class="form-control" />
</div>
<div class="form-group">
<label for="allDay">¿Todo el día?</label>
<input type="checkbox" value="true" name="allDay" th:field="*{allDay}" />
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
</div>
</div>
The Controller of /guardar/} + ${usuario.id_user}
#PostMapping("/guardar/{id}")
public String guardar(#Valid Event event, Errors errores,#PathVariable int id,Model model) throws ParseException {
/* if (errores.hasErrors()) {
return "agregar";
}*/
UserPlanD userPlanD = userService.encontrarUsuarioPorId(id);
model.addAttribute("usuario",userPlanD);
event.setUser(userPlanD);
Date inicio_evento = formatter.parse(event.getStartDate().toString());
String termino_evento = event.getStartDate().toString();
event.setStartDate(inicio_evento);
List<Event> eventicos = Arrays.asList(event);
System.out.println("Evento" + event + "y usuario: " + userPlanD);
eventService.guardar(event);
/*userPlanD.setEvents(eventicos);
userService.guardar(userPlanD);*/
return "redirect:/eventos";
}
The Model is the next one:
#Table(name="event_calendar")
public class Event implements Serializable {
//private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_event")
private Long id_event;
#Column(name = "title")
private String title;
#NotEmpty
private String e_description;
#NotEmpty
#JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSSSS")
#Column(columnDefinition = "DATETIME")
private Date startDate;
#NotEmpty
#JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSSSS")
#Column(columnDefinition = "DATETIME")
private Date endDate;
#NotEmpty
private String className;
#NotEmpty
private String icon;
#NotEmpty
private String allDay;
#ManyToOne
#JoinColumn(name = "id_user")
private UserPlanD user; ```
Here its a debug result of the controller result in the line the got the next code "System.out.println("Evento" + event + "y usuario: " + userPlanD)"
[1]: https://i.stack.imgur.com/QOYfW.png

Spring mvc form:form type data can't cast from Localdate to Date

I'm trying to create a simple "expense tracker" with spring mvc 5 and hibernate 5.
When I post without errors, I redirect towards the view and everything it's all right, but When I post and there is an error, the rendering of the view in the GET method fails, because of this:
InputTag - java.time.LocalDate cannot be cast to java.util.Date
How can I fix it?
I tried with converters, with initBinder override methods.. but nothing worked.
The field in the entity is annotated with #DateTimeFormat(pattern = "yyyy-MM-dd")
The field in mysql is DATETIME.
I've added an InitBinder to format the localDate in the controller..
Plus I can't find a similar issue on stackoverflow.
Deeply thank u!
I'm including the controller code:
#Controller
public class ExpensesController {
#Autowired
private ExpenseService expenseService;
#Autowired
private SecurityService securityService;
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
#RequestMapping(value = "/expCounter", method = RequestMethod.GET)
public String showExpensesCounter(Model model)
{
String userName = securityService.getLoggedUserUsername();
List<Expense> expenses = expenseService.findAllByUser(userName);
model.addAttribute("expenses", expenses);
if (!model.containsAttribute("expForm")) {
model.addAttribute("expForm", new Expense());
}
return "expenses-counter";
}
#RequestMapping(value = "/expCounter", method = RequestMethod.POST)
public String addExpense(#Valid #ModelAttribute("expForm") Expense expense,
BindingResult result,
ModelMap model, RedirectAttributes redirectAttributes)
{
if(result.hasErrors())
{
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.expForm", result);
redirectAttributes.addFlashAttribute("expForm", expense);
return "redirect:expCounter";
}
expenseService.save(expense);
return "redirect:expCounter";
}
}
This is the expense entity code:
#Entity
#Table(name = "expense")
public class Expense implements Serializable
{
private static final long serialVersionUID = -7179454458042397155L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name="user_id", nullable=false)
// #ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
#NotNull
#DecimalMax("1000000")
#Column(name = "amount")
private BigDecimal amount;
#Size(max = 250)
#Column(name = "description")
private String description;
#NotNull
#PastOrPresent
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Column(name = "on_date", columnDefinition = "DATETIME")
private LocalDate spentOnDate;
//Constructor, Getters and Setters omitted for brevity
And this is the form:
<form:form method="POST" action="expCounter" modelAttribute="expForm">
<div class="form-row mx-5 my-4 align-items-center text-center">
<div class="form-group col-4 text-uppercase">
<label class="control-label" for="description">
<p><spring:message code="expenses.counter.description"/></p>
</label>
<form:input path="description" cssClass="form-control" />
<form:errors path="description" />
</div>
<div class="form-group col-2 text-uppercase ${hasErrors ? 'has-error' : ''}">
<label class="control-label" for="amount">
<p><spring:message code="expenses.counter.amount"/></p>
</label>
<form:input path="amount" cssClass="form-control" />
<form:errors path="amount" />
</div>
<!-- THIS IS THE DATE FIELD-->
<div class="form-group col-2 text-uppercase">
<label class="control-label" for="spentOnDate">
<p><spring:message code="expenses.counter.txdate"/></p>
</label>
<spring:message code="expenses.placeholder.ondate" var="ondate.placeholder" />
<form:input type="date" path="spentOnDate" name="spentOnDate"
cssClass="form-control" placeholder='${ondate.placeholder}'/>
<form:errors path="spentOnDate" />
</div>
<div class="form-group col-2">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<form:button class="btn btn-secondary">
<spring:message code="general.button.submit"/>
</form:button>
</div>
</div>
I this it is a problem of DateFormatting.. because I specified the date format like yyyy-MM-dd (because in mysql I save it like that..) but when the post fails and I get the view (with the data field filled) spring cannot cast the existing LocalDate(yyyy-MM-dd) to java.util.date... but I don't know how to fix it.
I found a workaround: simply changed input tag from spring's form:form to:
<input type="date" class="form-control" name="spentOnDate" placeholder="${ondate.placeholder}"/>
It now works but would be a lot better to be able to use spring's form:form tag. Do you know how to fix it?
This way I could use the formatter on the FE.
<fmt:formatDate value="${expForm.spentOnDate}" var="installDate" pattern="dd/mm/yyyy" />

Hibernate saveOrUpdate-method creates new entry/row instead of updating the existing one

I'm currently making a website to provide product management for a registered user. It uses spring + hibernate + mysql + jsp. Hibernates saveOrUpdate-method creates always a new entry/row to the database for the ProductDetail-entity instead of updating the already existing one. I have done the mapping according to the tutorials out there and I cannot understand what makes it to create a new row, because I have established the relationships to the Product- and ProductDetail-entity (OneToOne) in the Controller layer before the use. Someone save me from this struggle, I have been stuck here for more than 3 months... Below I will provide pictures of the Entities, Controller and DAO.
Product Entity (nvm commented annotations)
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NotNull(message = "Product name is required")
#Size(min = 1, message = "is required")
#Column(name = "product_name")
private String productName;
#DecimalMin(value = "0.01", inclusive = true, message = "Price must be a minimum of 0.01$")
#Digits(integer = 6, fraction = 2, message = "Price out of bounds, limit <6 digits>.<2 digits>")
#Column(name = "price")
private float price;
#NotNull(message = "Quantity is required")
#Min(value = 1, message = "Must be greater than zero")
#Column(name = "qty")
private Integer quantity;
#NotNull(message = "Email is required")
#Email(message = "Provide a valid email address")
#Pattern(regexp = ".+#.+\\..+", message = "Provide a valid email address")
#Column(name = "added_by")
private String addedBy;
#Column(name = "creation_datetime")
private Date createDateTime;
//#Version
#Column(name = "last_updated")
private Date updateDateTime;
//#Valid
#OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private ProductDetail productDetail;
#Column(name = "value_in_stock")
private float valueInStock;
public Product() {
this.createDateTime = new Date();
this.updateDateTime = this.createDateTime;
}
public Product(String productName, float price, Integer quantity, String addedBy) {
this.productName = productName;
this.price = price;
this.quantity = quantity;
this.addedBy = addedBy;
this.valueInStock = this.price * this.quantity;
}
public void setProductDetail(ProductDetail productDetail) {
if (productDetail == null) {
if (this.productDetail != null) {
this.productDetail.setProduct(null);
}
} else {
productDetail.setProduct(this);
}
this.productDetail = productDetail;
}
// getters and setters
ProductDetail entity
#Entity
#Table(name = "product_detail")
public class ProductDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NotNull(message = "A descriptionis required")
#Column(name = "description")
private String description;
#NotNull(message = "Category is required")
#Column(name = "category")
private String category;
#DecimalMin(value = "0.001", inclusive = true, message = "Must a minimum of 0.001g")
#Digits(integer = 7, fraction = 2, message = "Weight out of bounds, limit <7 digits>.<2 digits>")
#Column(name = "weight_g")
private float weight;
#NotNull(message = "Manufacturer is required")
#Column(name = "manufacturer")
private String manufacturer;
#NotNull(message = "Provide a country")
#Column(name = "made_in_country")
private String countryMadeIn;
#OneToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private Product product;
public ProductDetail() {
}
public ProductDetail(String description, String category, String manufacturer, String madeIn) {
this.description = description;
this.category = category;
this.manufacturer = manufacturer;
this.countryMadeIn = madeIn;
}
// Getters and setters...
ProductController
Method to fetch form for adding a new product (GET request)
#GetMapping("/add")
public String getAddForm(Model model) {
// create model attribute to bind all form data
Product product = new Product();
ProductDetail productDetail = new ProductDetail();
// associating product and product details
product.setProductDetail(productDetail);
product.getProductDetail());
model.addAttribute("categoryMap", categoryOptions);
model.addAttribute("countryMap", countryOptions);
model.addAttribute("product", product);
return "product-form";
}
Method to fetch product by id from productService (delegates data fetching to productDAO) (GET request)
#GetMapping("/updateProduct")
public String getUpdateForm(#RequestParam("productId") int productId, Model model) {
// get product from db
Product product = productService.getProduct(productId);
product.getProductDetail());
// set product as a model to pre-populate the form
model.addAttribute("categoryMap", categoryOptions);
model.addAttribute("countryMap", countryOptions);
model.addAttribute("product", product);
return "product-form";
}
Method to process saving/updating the Product and its ProductDetail (POST request)
#PostMapping("/save")
public String saveOrUpdate(#Valid #ModelAttribute("product") Product product, BindingResult bindingResult,
Model model) {
// if result set has errors, return to product form with errors
if (bindingResult.hasErrors()) {
model.addAttribute("categoryMap", categoryOptions);
model.addAttribute("countryMap", countryOptions);
return "product-form";
} else {
// calculate value in stock to product before saving
product.setValueInStock();
productService.saveProduct(product);
return "redirect:/";
}
}
ProductDAOImpl
Method to saveOrUpdate given product
#Override
public void saveProduct(Product product) {
// get current hibernate session
Session session = sessionFactory.getCurrentSession();
// save or update given product
session.saveOrUpdate(product);
}
Method to fetch product by its id
#Override
public Product getProduct(int id) {
// get current hibernate session
Session session = sessionFactory.getCurrentSession();
Query<Product> query =
session.createQuery("SELECT p FROM Product p "
+ "JOIN FETCH p.productDetail "
+ "WHERE p.id=:productId",
Product.class);
// set parameters in query
query.setParameter("productId", id);
// execute and get product
Product product = query.getSingleResult();
return product;
}
And finally here is the JSP form itself
<form:form action="save" modelAttribute="product" method="POST">
<!-- associate data with product id -->
<form:hidden path="id" />
<div class="form-group row">
<label for="nameInput" class="col-sm-2 col-form-label">Product name *:</label>
<div class="col-sm-10">
<form:input path="productName" cssClass="form-control" id="nameInput" placeholder="Enter name" />
<form:errors path="productName" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="priceInput" class="col-sm-2 col-form-label">Price($) *:</label>
<div class="col-sm-10">
<form:input path="price" cssClass="form-control" id="priceInput" placeholder="Enter price" />
<form:errors path="price" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="quantityInput" class="col-sm-2 col-form-label">Quantity *:</label>
<div class="col-sm-10">
<form:input path="quantity" cssClass="form-control" id="quantityInput" placeholder="Enter qty" />
<form:errors path="quantity" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="emailInput" class="col-sm-2 col-form-label">Added by(email) *:</label>
<div class="col-sm-10">
<form:input path="addedBy" cssClass="form-control" id="emailInput" placeholder="example.address#email.com" />
<form:errors path="addedBy" cssClass="errors" />
</div>
</div>
<div id="separator" > </div>
<h5 id="header" >Product Details (Can be updated later)</h5>
<div class="form-group row">
<label for="categoryInput" class="col-sm-2 col-form-label">Category *:</label>
<div class="col-sm-3">
<form:select path="productDetail.category" id="categoryInput" cssClass="form-control">
<form:option value="" label="Select Product Category" />
<form:options items="${categoryMap}"/>
</form:select>
<form:errors path="productDetail.category" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="manufacturerInput" class="col-sm-2 col-form-label">Manufacturer *:</label>
<div class="col-sm-4">
<form:input path="productDetail.manufacturer" cssClass="form-control" id="manufacturerInput" placeholder="Enter manufacturer" />
<form:errors path="productDetail.manufacturer" cssClass="errors" />
</div>
<label for="madeInInput" class="col-sm-2 col-form-label">Country *:</label>
<div class="col-sm-3">
<form:select path="productDetail.countryMadeIn" id="madeInInput" cssClass="form-control">
<form:option value="" label="Country manufactured in" />
<form:options items="${countryMap}"/>
</form:select>
<form:errors path="productDetail.countryMadeIn" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="descriptionInput" class="col-sm-2 col-form-label">Description *:</label>
<div class="col-sm-10">
<form:textarea path="productDetail.description" cssClass="form-control" id="descriptionInput" placeholder="Short description of product..." />
<form:errors path="productDetail.description" cssClass="errors" />
</div>
</div>
<div class="form-group row">
<label for="weightInput" class="col-sm-2 col-form-label">Weight(g):</label>
<div class="col-sm-10">
<form:input path="productDetail.weight" cssClass="form-control" id="weightInput" placeholder="Enter weight" />
</div>
</div>
<input type="submit" value="Add" class="btn btn-primary" />
</form:form>
So the user should be able to add and update a product. At the moment this just adds and when the user wants to update the product, it just creates a new ProductDetail-entity instead of updating the ProductDetail on the fetched Product-entity.
This is because you are using primitive data type int. Update it to Integer and it should work fine.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
Update it to,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
NOTE : Regenerate the corresponding getter/setters for this field.
You need to add a hidden key for productDetail.id or else it considers product detail object to be a transient one and saves it as a new object instead of updating it.

Number data is not binding in Spring MVC

While working on a spring MVC based project I am trying to bind data from JSP to model.
While the string data is binding perfectly for some reason the number data is not binding at all.
I have checked the parameter name it's same in POJO and JSP
Below is my controller code
#RequestMapping(value = "/investor-signup", method = RequestMethod.GET)
public String registration(Model model) {
model.addAttribute("investor", new InvestorRegister());
return "investor-signup";
}
#RequestMapping(value = "/investor-signup", method = RequestMethod.POST)
public String registration(#ModelAttribute("investor") InvestorRegister investor, BindingResult bindingResult, Model model) {
System.out.println(investor.getFULL_NAME());
System.out.println(investor.getMOB_NO());
investorRegisterService.save(investor);
return "redirect:/login";
}
Below is my JSP code
<form:form method="post" action="investor-signup"
modelAttribute="investor" id="contact-form"
style="padding-top: 40px;" role="form" class="formcss" align="left">
<div class="controls">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<div class="col-md-2 ">
<label for="user_name">Full Name *</label>
</div>
<div class="col-md-10 p0">
<input id="user_name" type="text" name="FULL_NAME" class="form-control" required="required" data-error="Full Name is required.">
</div>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<div class="col-md-2">
<label for="user_mobile">Mobile *</label>
</div>
<div class="col-md-6 ">
<input id="user_mobile" type="number" name="MOB_NO" class="form-control" required="required" data-error="Mobile No is required.">
</div>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-12" align="center">
<input type="submit" class="btn btn-success btn-send" value="Register">
</div>
</div>
</form:form>
Below is my model POJO
#Entity
#Table(name = "InvestorRegister")
public class InvestorRegister {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GEN")
#SequenceGenerator(name = "SEQ_GEN", sequenceName = "IID_SEQ")
#Column(name = "ID")
private int ID;
#NotEmpty
#Column(name = "FULL_NAME")
private String FULL_NAME;
#Column(name = "MOB_NO")
private int MOB_NO;
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
public String getFULL_NAME() {
return FULL_NAME;
}
public void setFULL_NAME(String fULL_NAME) {
FULL_NAME = fULL_NAME;
}
public int getMOB_NO() {
return MOB_NO;
}
public void setMOB_NO(int mOB_NO) {
MOB_NO = mOB_NO;
}
}
While the string data is binding perfectly for some reason the number data is not binding at all
I have checked the parameter name it's same in POJO and JSP
Any help is appreciated.
#abhi314, Have you just tried by extracting field separately ?
I mean have you tried any of these just to check value comes from view side or not?
public String registration(#RequestParam("FULL_NAME") String FULL_NAME, #RequestParam("MOB_NO") int MOB_NO) {
//check value comes or not
}
OR
public String registration(#RequestBody InvestorRegister ir) {
//check value comes or not
}
Please do let me know if you get value or not by checking this way
You need to use Wrapper Integer instead of int.
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GEN")
#SequenceGenerator(name = "SEQ_GEN", sequenceName = "IID_SEQ")
#Column(name = "ID")
private Integer ID;
Also I would suggest to use naming convention standards. Instead of ID declare id or most preferred as investorRegisterId.
After changing from int to Integer please regenerate the getter/setters for the same.
Your actual issue is failing on the concept of Java auto-boxing/unboxing.

Not able to persist the role mapped to the user

I am creating an application with Spring 4, Hibernate 4 having Spring security
Users have roles assigned to them, but when I tried to create the user, it not able to save the user it is giving me exception on Browser below the field of role
Failed to convert property value of type [java.lang.String[]] to required type [java.util.Set] for property userRoles; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type
[#org.hibernate.validator.constraints.NotEmpty #javax.persistence.ManyToMany #javax.persistence.JoinTable com.himanshu.blogger.model.Role] for value 2; nested exception is java.lang.StackOverflowError
My User model class
#Entity
#Table(name = "BLOG_USER")
public class User {
#Id
#Column(name = "USER_ID")
private String userId;
#NotEmpty
#Column(name = "PASSWORD")
private String password;
#NotEmpty
#Column(name = "FIRST_NAME")
private String firstName;
#NotEmpty
#Column(name = "MIDDLE_NAME")
private String middleName;
#NotEmpty
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "EMAIL")
private String email;
#Column(name = "PHONE")
private String phone;
#NotNull
#Column(name = "STATE")
private Integer state = State.ACTIVE.getState();
#Transient
private String stateName;
#NotEmpty
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_ROLE_MAP", joinColumns = { #JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "ROLE_ID") })
private Set<Role> userRoles = new HashSet<>();
/*skipped getter, setters and some utility methods*/
Role model class
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="ROLE_ID")
private Integer roleId;
#Column(name="ROLE_TYPE", length=20, nullable=false, unique=true)
private String roleType=RoleType.USER.getRoleType();
/*skipped getters and setters*/
My controller methods for registering new user here I have added a model attribute also to load the roles in registration form
/**
* This method will provide the medium to add a new user.
* By GET method it will identify that it has to load registration page
*/
#RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
public String newUser(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", false);
return "registration";
}
/**
* This method will be called on form submission, handling POST request for
* saving user in database. It also validates the user input
*/
#RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(#Valid User user, BindingResult result, ModelMap model) {
System.out.println("save user : "+user);
if (result.hasErrors()) {
return "registration";
}
if(!userService.isUniqueUser(user.getUserId())){
FieldError userIdError =new FieldError("user","userId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getUserId()}, Locale.getDefault()));
result.addError(userIdError);
return "registration";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
//return "success";
return "registrationsuccess";
}
#ModelAttribute("blogRoleList")
public List<Role> initializeProfiles() {
return roleService.findAll();
}
I have registered a convertor to convert role id to Role object
#Component
public class RoleIdtoRoleConverter implements Converter<Object, Role> {
#Autowired
RoleService roleService;
public Role convert(Object roleIdObj) {
System.out.println("covertor called with id " + roleIdObj.toString());
Integer roleId = -1;
try {
roleId = Integer.parseInt((String) roleIdObj);
} catch (NumberFormatException e) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(Role.class), roleIdObj, null);
}
System.out.println("covertor called with id " + roleIdObj.toString());
Role role = roleService.findRoleById(roleId);
System.out.println("Role = " + role);
return role;
}
Registered this convertor in my config class
#Autowired
RoleIdtoRoleConverter roleIdToRoleConverter;
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(roleIdToRoleConverter);
}
Registration JSP file registration.jsp
<form:form method="POST" modelAttribute="user" class="form-horizontal">
<%-- <form:input type="hidden" path="userId" id="useId"/> --%>
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="firstName">First Name</label>
<div class="col-md-7">
<form:input type="text" path="firstName" id="firstName" class="form-control input-sm"/>
<div class="has-error">
<form:errors path="firstName" class="help-inline"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="lastName">Last Name</label>
<div class="col-md-7">
<form:input type="text" path="lastName" id="lastName" class="form-control input-sm" />
<div class="has-error">
<form:errors path="lastName" class="help-inline"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="userId">User ID</label>
<div class="col-md-7">
<c:choose>
<c:when test="${edit}">
<form:input type="text" path="userId" id="userId" class="form-control input-sm" disabled="true"/>
</c:when>
<c:otherwise>
<form:input type="text" path="userId" id="userId" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userId" class="help-inline"/>
</div>
</c:otherwise>
</c:choose>
</div>
</div>
</div>
<c:if test="${!edit}">
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="password">Password</label>
<div class="col-md-7">
<form:input type="password" path="password" id="password" class="form-control input-sm" />
<div class="has-error">
<form:errors path="password" class="help-inline"/>
</div>
</div>
</div>
</div>
</c:if>
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="email">Email</label>
<div class="col-md-7">
<form:input type="text" path="email" id="email" class="form-control input-sm" />
<div class="has-error">
<form:errors path="email" class="help-inline"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="userRoles">Roles</label>
<div class="col-md-7">
<form:select path="userRoles" items="${blogRoleList}" multiple="true" itemValue="roleId" itemLabel="roleType" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userRoles" class="help-inline"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-actions floatRight" style="margin-left: 25px">
<c:choose>
<c:when test="${edit}">
<input type="submit" value="Update" class="btn btn-primary btn-sm"/> or Cancel
</c:when>
<c:otherwise>
<input type="submit" value="Register" class="btn btn-primary btn-sm"/> or Cancel
</c:otherwise>
</c:choose>
</div>
</div>
</form:form>
But am not able to figure out it is not able to save the data, I have printed the user object in controller it is showing Roles as blank array, did I am missing some things here, not able to get, any help and suggestions will be got.
Adding Code for saving user
Abstract dao class
public class AbstractDao <PK extends Serializable, T>{
private final Class<T> persistantClass;
#Autowired
SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public AbstractDao() {
this.persistantClass=(Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
public void persistEntity(T entity) {
this.getSession().persist(entity);
}
/* mor emethods to load data on based on object type */
}
User Dao implimentation calss
#Repository("userDao")
public class UserDaoImpl extends AbstractDao<String, User> implements UserDao{
#Override
public void saveUser(User user) {
persistEntity(user);
}
/* more methods for fetching data from db*/
}
Thanks.
I got the problem with my application.
The problem was with the dao method which was there to get role object from DB,
by mistake while writing the code I did made the call to same method, which executing recursively, so convertor was not able to get the role object from DB.

Categories