Map HTML input date to LocalDate of Java Object - java

I have a input field (type: 'date') - who could I map it to a 'LocalDate' field in my Object using Thymeleaf?
Object
public class Project {
#Id
private int id;
private LocalDate startDate;
private LocalDate endDate;
}
HTML input
<form action="#"
th:action="#{|/admin/projects/add/save|}"
th:object="${newProjects}"
method="POST"
class="form-horizontal">
<input type="date" class="form-control" id="startDate"
placeholder="Project start"
th:field="*{startDate}"/>
<input type="date" class="form-control" id="endDate"
placeholder="Project start"
th:field="*{endDate}"/>
</form>
How could I map the input field correctly to the LocalDate startDate or endDate?
Controller
//GetMapping for Projects is also there, but I didn't paste it to keep clarity
#PostMapping("/add/save")
public String saveProject(#Valid #ModelAttribute("project") Project project,
BindingResult bindingResult,
Model model,
RedirectAttributes redirectAttributes) {
// bindingResult has error, because Thymeleaf can't map from the input-field to startDate
if (!bindingResult.hasErrors()) {
project.save(project);
return "redirect:/admin/projects/list";
} else {
return "admin/projects/add";
}
}
Exception
Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'startDate'; nested
exception is
org.springframework.core.convert.ConversionFailedException: Failed to
convert from type [java.lang.String] to type
[#javax.persistence.Column java.time.LocalDate] for value
'2017-09-08'; nested exception is java.lang.IllegalArgumentException:
Parse attempt failed for value [2017-09-08]

You have a few options:
1 - Try:
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
2 - Use Thymeleaf Extras

Adding #DateTimeFormat(pattern = "yyyy-MM-dd") annotation to LocalDate variable solves the problem.

You can only bind Model Objects which can be defined with simple types. when the object serialized from the client side to the server , It has no knowledge about the complex types(like java.time.LocalDate) unless they are expressed interms of simple types. For your scnerio the best way is to map the client side HTML with the server side java object Dates' as String. You can then convert the String object into java.time.LocalDate in the server side Controller class or any java service class.

Related

Spring/Thymeleaf - Failed to convert value of type 'java.lang.String' to required type

I am new to Spring and Thymeleaf, and I do not know what went wrong here.
When submitting my form, I get THIS error:
There was an unexpected error (type=Bad Request, status=400). Failed to convert value of type 'java.lang.String' to required type 'br.com.teste.segware.domain.post.Post'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'Some text...'; nested exception is java.lang.NumberFormatException: For input string: "Sometext..." org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'br.com.teste.segware.domain.post.Post'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value 'Some text...'; nested exception is java.lang.NumberFormatException: For input string: "Sometext..."
Here is my Post class: (I use Lombok, so the getters and setters are self-generated)
#Getter
#Setter
#Entity
#Table(name = "post")
public class Post implements Serializable {
#EqualsAndHashCode.Include
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Integer id;
#NotBlank
#Column(nullable = false)
private String nome;
#NotBlank
#Size(max = 800)
#Column(nullable = false)
private String post;
}
My Controller:
#Controller
public class IndexController {
#Autowired
private PostService postService;
#PostMapping("/savePost")
String savePost(#ModelAttribute("post") Post post) {
postService.savePost(post);
return "redirect:/";
}
}
And my HTML form:
<form method="post" th:object="${post}" th:action="#{/savePost}">
<fieldset>
<input type="hidden" th:field="*{id}" />
<label for="name">Nome:</label> <br/>
<input type="text" id="name" name="name" th:field="*{nome}" placeholder="Nome..." /> <br/><br/>
<label for="post">O que vocĂȘ gostaria de dizer?</label> <br/>
<textarea id="post" name="post" th:field="*{post}" ></textarea> <br/><br/>
<input type="submit" value="Postar" />
</fieldset>
</form>
Why is this thing trying to convert the <textarea> from String to some number with NumberFormat stuff ?
The Entity named Post clearly declares the field post as a String. So why does Spring thinks it is some kind of Number when submitting? Obviously, when I put some numbers in textarea, it saves to the database. But I need String to be saved...
Someone please enlighten me.
Thanks in advance!
EDIT
Here is the Repository AND Service Class, just to be sure.
Service...
#Service
public class PostService {
#Autowired
private PostRepository postRepository;
public void savePost(Post post) {
postRepository.save(post);
}
}
Repo...
public interface PostRepository extends JpaRepository<Post, Integer> {
}
There seems to be a name collision since both the object name and the variable name are same (in your case, post).
Either change the column name in the entity class to other than post and then change in the html. Or, change the backing object name in the controller and html to something other than post. Both are working for me.

#DateTimeFormat and TO_DATE() pattern for Calendar type passed through rest service

I'm working on Web application which is using Spring Data JPA and Oracle Database. I was using #RepositoryRestResource annotation in interface where I was just declaring some query methods with named parameters using #Param and #Query annotations. Today I needed to add a new entity with the dates. In database one column is type of DATE and the other one is type of TIMESTAMP. And below the Java representation of this two columns only, of course with all setters and getters, but it has more fields so just adding this:
#Temporal(TemporalType.DATE)
#Column(name = "INIT_DATE")
private Calendar initDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "AGG_DATE")
private Calendar aggDate;
I also created new interface for case, the same way as always:
#RepositoryRestResource(collectionResourceRel = "customer", path = "customer")
public interface ICustomerRepository extends PagingAndSortingRepository<Customer, Long> {
#Query("SELECT c FROM Customer c where c.initDate <= TO_DATE(:currentDate, 'yyyy-MM-dd') AND c.aggDate >= TO_DATE(:currentDate, 'yyyy-MM-dd')")
public List<Customer> filterByDate(#Param("currentDate") #DateTimeFormat(pattern = "yyyy-MM-dd") Calendar currentDate);
}
I also tried other format, but I'm receiving this error:
ORA-01830: date format picture ends before converting entire input string
I'm trying to get this data from database using this http request:
http://localhost/webApp/customer/search/filterByDate?currentDate=2017-07-10
And to be honest, I have no idea what is the problem here... The format date in the database is yy/MM/DD, but it also wasn't working for me... Could you tell me what I'm missing or doing wrong??

LocalDate in form

I have a question about Spring + Thymeleaf date format.
I have a simple entity with LocalDate date field. I want to get this date from a user in form and save it to MySQL database.
I'm getting such an error:
Failed to convert property value of type java.lang.String to required type java.time.LocalDate for property date; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.time.LocalDate for value 2019-04-30; nested exception is java.time.format.DateTimeParseException: Text 2019-04-30 could not be parsed at index 2
My entity:
#Entity
#Table(name="game")
public class Game{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Transient
private User gameOwner;
private LocalDate date;
private LocalTime time;
//other fields
Thymeleaf view / form:
<form action="#" th:action="#{/games/addForm}" th:object="${gameForm}" method="post">
<p>Date: <input type="date" th:field="*{date}" /></p>
</form>
What's the reason for this problem? Maybe there is the other, better way to storage date?
Problem solved..
I don't know why but changing my template to:
<input type="date" th:value="*{date}" th:field="*{date}" />
and adding #DateTimeFormat(pattern = "yyyy-MM-dd") to entity field solved the problem.
import org.springframework.format.annotation.DateTimeFormat;
add the following annotation above date.
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
put additional curly bracket around date. It will convert date into string
<form action="#" th:action="#{/games/addForm}" th:object="${gameForm}" method="post">
<p>Date: <input type="date" th:field="*{{date}}" /></p>
</form>
I'm unable to reproduce the exact error, but I believe that adding a custom editor for the LocalDate class should fix this. Add this method to your controller:
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
#Override
public void setAsText(String text) throws IllegalArgumentException{
setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
#Override
public String getAsText() throws IllegalArgumentException {
return DateTimeFormatter.ofPattern("yyyy-MM-dd").format((LocalDate) getValue());
}
});
}
It's also possible to add this globally, you'll have to create a ControllerAdvice class and add the method there instead.
Thymeleaf provides an extra module for that: https://github.com/thymeleaf/thymeleaf-extras-java8time
Adding the following dependency (maven) should be enough:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

Spring Data (Rest): Date serialization mapping returns a wrong value

I use Spring Boot and Data Rest to create a simple microservice in Java8 and get a wrong serialized value in a Date attribute in my JSON response.
My entity:
#Entity
public class ArchivedInvoice implements Serializable {
...
#Column
private java.util.Date invoiceDate;
...
}
My repository interface:
#RepositoryRestResource(collectionResourceRel = "archivedinvoices", path = "archivedinvoices")
public interface ArchivedInvoiceRepository extends PagingAndSortingRepository < ArchivedInvoice, Long > {
...
#RestResource(rel = "findByDate", path = "findByDate")
public Page< ArchivedInvoice > findByInvoiceDate(#Param("invoiceDate") #Nullable #DateTimeFormat(iso = ISO.DATE) Date invoiceDate, Pageable pageable);
...
}
Postgres saves the attribute in a simple date (invoice_date date NOT NULL - '2016-02-22') but the JSON response returns:
"invoiceDate" : "2016-02-21T23:00:00.000+0000"
How can I avoid this?
java.util.Date is actually a timestamp:
The class Date represents a specific instant in time, with millisecond
precision.
Use java.sql.Date instead if the SQL type is date.
Or if you use java 8, you can try using java.time.LocalDate. For that to work you will need to register Springs JSR310 JPA converters.

How to implement correct data binding in controller?

I have a jsp page which combines User object using forms. On the last form I'm trying to get Collection<Permission>. But when I'm trying to pass data to controller I'm getting 400 Error because of:
Field error in object 'user' on field 'permissions':
rejected value [add,view];
codes [typeMismatch.user.permissions,typeMismatch.permissions,typeMismatch.java.util.Collection,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.permissions,permissions];
arguments [];
default message [permissions]];
default message [Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.Collection' for property 'permissions'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [it.marco.javaproject.domain.Permission] for property 'permissions[0]': no matching editors or conversion strategy found]
Here is my jsp form:
<form:form action="/user/permission" method="POST" modelAttribute="user">
<form:checkboxes path="permissions" items="${permissions}" delimiter=<br>"/>
<form:hidden path="email"/>
<form:hidden path="password"/>
<form:hidden path="name"/>
<input type="submit" value="Next" name="next"/>
</form:form>
Part of controller:
public String processRoleForm(#ModelAttribute("user") User user, ModelMap model) {
model.addAttribute("permissions", userService.getPermissions());
return "user/form/permissionForm";
}
Permission class:
#Entity
#Table(name = "permission")
public class Permission implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "name")
private String name;
If I'm not mistaken I need to use some kind of data binder in my controller. How to implement it? How to properly translate String[] to Collection of Permission?
I find simple solution. Here it is:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Permission.class, new PropertyEditorSupport() {
#Override
public void setAsText(String id) throws IllegalArgumentException {
setValue(userService.getPermission(Integer.parseInt(id)));
}
});
}

Categories