BindingResult requires dates input even without not null or validation - spring

I got an issue with a web application in Spring.
I am writing a search jsp form with related controller and service.
I do not need some datas to be necessary, and it goes all fine but dates.
It requires me to insert dates into dates input tags, if I leave that boxes empty I got an error in BindingResult and my search service stops.
Why does it not accept empty values?
In the domain the attributes are not set to NotNull, and I even remove the #Valid annotation from the service, but it does continues to ask me for some datas into that fields.
Can anyone try to explain me where should I look to solve this issue?
Here is the code:
jsp form:
<form:form commandName="colloquioRicerca" action="colloquio_ricerca" method="post">
<fieldset>
<legend>Cerca un colloquio</legend>
<p class="errorLine">
<form:errors path="codiceFiscale" cssClass="error"/>
</p>
<p>
<label for="codiceFiscale">Codice Fiscale del Docente: </label>
<form:input id="codiceFiscale" path="codiceFiscale" tabindex="1"/>
</p>
<h5>Ricerca avanzata:</h5>
<p>
<label for="nome">Nome:<br><small>(accetta parziali)</small> </label>
<form:input id="nome" path="nome" tabindex="2"/>
</p>
<p>
<label for="cognome">Cognome:<br><small>(accetta parziali)</small></label>
<form:input id="cognome" path="cognome" tabindex="3"/>
</p>
<p>
<label for="dataColloquio">Cerca per data: </label>
<form:input id="dataColloquio" path="dataColloquio" tabindex="4" placeholder="dd/MM/yyyy"/>
</p>
<p>Cerca per periodo:</p>
<p>
<label for="dataIniz">Dal:</label>
<form:input id="dataIniz" path="dataIniz" tabindex="5" placeholder="dd/MM/yyyy"/>
<label for="dataFin">Al:</label>
<form:input id="dataFin" path="dataFin" tabindex="6" placeholder="dd/MM/yyyy"/>
</p>
<p>
<label for="esitoColloquio">Al:</label>
<form:input id="esitoColloquio" path="esitoColloquio" tabindex="7" placeholder="dd/MM/yyyy"/>
<!--
<label for="esitoColloquio">Esito del Colloquio:</label>
<form:select id="esitoColloquio" name="esitoColloquio" path="esitoColloquio" tabindex="7">
<form:option value="positivo" >Positivo</form:option>
<form:option value="negativo" >Negativo</form:option>
<form:option value="altro"></form:option>
</form:select>-->
</p>
<p id="buttons">
<input id="reset" type="reset" tabindex="8">
<input id="submit" type="submit" tabindex="9"
value="Search">
</p>
</fieldset>
</form:form>
domain:
public class ColloquioSearch {
#Size(min=16, max=16)
private String codiceFiscale;
private String nome;
//#Size(min=1, max=50)
private String cognome;
private Date dataColloquio;
private Date dataIniz;
private Date dataFin;
private String esitoColloquio;
service:
public List<Colloquio> getAllColloquio()
throws SQLException {
List<Colloquio> result = new ArrayList<Colloquio>();
Statement s= con.createStatement();
ResultSet rs = s.executeQuery(
"SELECT doc.codice_fiscale, col.data_colloquio, col.esito_colloquio, col.note_colloquio FROM colloqui_pj col, docenti_pj doc where doc.id_docente=col.id_docente");
while(rs.next());{// il getTime per convertirla in util.date
result.add(new Colloquio(rs.getString(1), rs.getTime(2), rs.getString(3), rs.getString(4)));
System.out.println("rs has next");
}
return result;
}
search method called by submit button:
#RequestMapping(value="prova")
public String goSearch(Model model){
logger.info("here we are");
model.addAttribute("colloquioRicerca", new ColloquioSearch());
return "ColloquioSearchForm";
}
#RequestMapping(value="colloquio_ricerca")
public String cerca(#ModelAttribute ColloquioSearch colloquioRicerca, BindingResult br, Model model){
logger.info("modelattribute:"+colloquioRicerca.toString()+"/"+colloquioRicerca.getCodiceFiscale());
logger.info("entered");
if (br.hasErrors()) {
FieldError fieldError = br.getFieldError();
logger.info("Code:" + fieldError.getCode() + ", object:"
+ fieldError.getObjectName() + ", field:"
+ fieldError.getField()+"siamo qui");
model.addAttribute("colloquioRicerca", colloquioRicerca);
return "ColloquioSearchForm";
}//validare datafine minore data inizio
String codiceFiscale = colloquioRicerca.getCodiceFiscale();/*
Date dataColloquio = colloquioRicerca.getDataColloquio();
Date dataIniz = colloquioRicerca.getDataIniz();
Date dataFin = colloquioRicerca.getDataFin();*/
String nome = "%"+colloquioRicerca.getNome()+"%";
String cognome = "%"+colloquioRicerca.getCognome()+"%";
String esitoColloquio = colloquioRicerca.getEsitoColloquio();
Colloquio colloquioTrovato = null;
logger.info("siamo prima dell'if isEmpty");
if (!codiceFiscale.isEmpty()){
logger.info("dentro if is empty");
try{
logger.info("dentro il try:"+colloquioRicerca.getCodiceFiscale());
List<Colloquio> lista = colloquiService.getAllColloquio();
if(lista.isEmpty()){logger.info("lista nulla");}
for(Colloquio colloquio : lista){
logger.info("colloquio su db cf:"+colloquio.getCodiceFiscale());
if(colloquio.getCodiceFiscale().equals(codiceFiscale)){
colloquioTrovato=colloquio;
logger.info("siamo dentro l'if: colloquio trovato"+colloquioTrovato.getCodiceFiscale());
}
}
}
catch(SQLException e){logger.info(e.getMessage()+"siamo qui?");}
}
if (colloquioTrovato == null){
model.addAttribute("colloquioRicerca", colloquioRicerca);
return "ColloquioSearchForm";
}
return "Daje";
}
Below is the error I got in console when jsp processing stops:
/*dic 21, 2016 9:52:00 AM project.controller.ColloquioSearchController cerca
INFORMAZIONI: modelattribute:project.domain.search.ColloquioSearch#5d2ca87b/hereitwritesthecorrectparam
dic 21, 2016 9:52:00 AM project.controller.ColloquioSearchController cerca
INFORMAZIONI: entered
dic 21, 2016 9:52:00 AM project.controller.ColloquioSearchController cerca
INFORMAZIONI: Code:typeMismatch, object:colloquioSearch, field:dataColloquiosiamo qui
dic 21, 2016 9:52:00 AM org.springframework.web.servlet.tags.form.InputTag doStartTag
GRAVE: Neither BindingResult nor plain target object for bean name 'colloquioRicerca' available as request attribute*/
above is the error I got in console since i leave empty the date fields on form; I got the error for DataColloquio, then for DataFin, and then for DataIniz, subsequently. The only way to avoid this error is by filling the form imput fields related
I hope to be into the lines of this site asking for this, thank You all.
P.S.: I know the code is bad structured, and it is not a good way to code the way it is written, I just wanted to explain the issue, meanwhile I am changing the structure, I just do not understand why it is asking me for not leaving empty date fields, and not the others.

It might be better if you print these
Date dataColloquio = colloquioRicerca.getDataColloquio();
Date dataIniz = colloquioRicerca.getDataIniz();
Date dataFin = colloquioRicerca.getDataFin();
directly in your controller, as I kinda doubt that spring will parse the string format coming from your input into Date object without customization.
In short, if you want to bind the Date fields you could register custom data binding for the date via WebDataBinder by simply adds
#InitBinder
public void initBinder(WebDataBinder webDataBinder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
in your controller, with this, even if your input is empty, spring will do the rest for you. You have to notice that the format would be yyyy-MM-dd or just change it if you want. As an alternative, you can also do
#DateTimeFormat(pattern = "yyyy-MM-dd") // Spring 4.0
private LocalDate dataColloquio;
#DateTimeFormat(pattern = "yyyy-MM-dd") // Spring 4.0
private LocalDate dataIniz;
#DateTimeFormat(pattern = "yyyy-MM-dd") // Spring 4.0
private LocalDate dataFin;
And about your error, this probably caused from your service as there's a rs.getTime(..) there, meanwhile the string date from your input cannot be parsed correctly into Date object thus your model object cannot be targetted hence thrown error. As previous my suggestion, try to put #InitBinder annotated method that I give above into your controller and let's hope it solves everything.

Related

Form with a select (drop-down) doesn't show error code

I have a form that contains a select to list all teachers by id in the system but it is not working properly.
Here is the code part of the form
and the corresponding path controller requests
I'm Using Thymeleaf and Spring Boot, so 'pr' corresponds a name for a variable of a repository of teachers.
<form th:action="#{/professor/updateProfessor/}" method="post" th:object="${professor}">
<div class= "form-group">
<label th:for = "id">Id</label>
<select th:field="*{id}">
<option
th:value = "${id}"
th:text = "${professor.id}">
</option>
</select>
</div>
<input type = "submit" value = "Add Professor">Save</button>
</form>
#GetMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView professorSelecao(){
ModelAndView atualizaProfessor = new ModelAndView("/atualizaProfessor");
atualizaProfessor.addObject("Add Professor");
return atualizaProfessor;
}
#PostMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView selecaoProfessor(){
ModelAndView pagSucesso = new ModelAndView("/pagSucesso");
pagSucesso.addObject(pr.findAll());
return pagSucesso;
}
From your controller, send a list of professors as per following to your view. Here you are associating the list of professors to the "professorList" :
model.addAttribute("professorList", pr.findAll());
And then to access above "professorList" in your thymeleaf do (similar to) this :
<option th:each="professor: ${professorList}" th:value="${professor}"> </option>
Not a full code but i hope you got the idea to get started.
For a full example, take a look here and here.
First of all what is not working? because I see a lot of things that may not work maybe because I don't see the all code or I am guessing some things, let's see
When you enter to your controller using
localhost:8080/professor/selecionaProfessor
are you expecting to use the form you put right? (the next code)
<form th:action="#{/professor/updateProfessor/}" method="post" th:object="${professor}">
<div class= "form-group">
<label th:for = "id">Id</label>
<select th:field="*{id}">
<option
th:value = "${id}"
th:text = "${professor.id}">
</option>
</select>
</div>
<input type = "submit" value = "Add Professor">Save</button>
</form>
because if that's correct you have a problem in your method:
#GetMapping(value = {"/selecionaProfessor"})
#ResponseBody
public ModelAndView professorSelecao(){
ModelAndView atualizaProfessor = new ModelAndView("/atualizaProfessor");
atualizaProfessor.addObject("Add Professor");
return atualizaProfessor;
}
you will get an error saying:
Neither BindingResult nor plain target object for bean name 'professor' available as request attribute
So you're missing to add the Key professor and a List so change:
atualizaProfessor.addObject("Add Professor");
with something like:
atualizaProfessor.addObject("professor", someListOfProfessorHereFromTheService (List<Professor>));
and it should work if your profesor object have the attributes you have on your form.
Now let's suppose that that worked before and the error wasn't that.
When you enter to your form if you see here:
form th:action="#{/professor/updateProfessor/}"
you're using updateProfessor I don't see that on your controller you have
#PostMapping(value = {"/selecionaProfessor"})
So I think that you should change the url mapping inside the html page or the controller and use the same as error 1, map the object using a key and value and iterate the list into the html as I showed in the 1st error
Hope it helps

Form input type DateTime using Thymeleaf + Spring MVC issue

I am struggling to use a Java LocalDateTime scheduledDateTime in a Thymeleaf form and getting it back to save it in the database. I get the following error message :
Bean property 'campaignExecution' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
It is really due to the datetime field. If I remove it from the html form everything works fine and I see the data from the object created in the controller.
My object contains the following along with the getter and setter returning thetype (LocalDateTime) :
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
private LocalDateTime scheduledDateTime;
My Controller initialize the value to now()
#RequestMapping({ "/campaign1"})
public String requestCampaign1(Model model) {
CampaignExecution ce = new CampaignExecution();
LocalDateTime localDateTime = LocalDateTime.now();
ce.setScheduledDateTime(localDateTime);
model.addAttribute("campaignExecution", ce);
And this is the form :
<form id="f" name="f" th:action="#{/campaign1}"
th:object="${campaignExecution}" method="post">
<div>
Schedule a date :
<input type="datetime-local" th:field=*{campaignExecution.scheduledDateTime} />
</div>
<hr>
<div>Parameters</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Much easier than I was thinking. For th:field you cannot use multiple object but only the "form object". I was using the full qualifier : object name.property name.

Spring Boot error while submitting form

I'm trying to add a table to the database via a form. The entity being created is called Album and it has 2 fields, Artist and Genre. Each of these two are separate entities. These 2 fields are annotated with #ManyToOne
#ManyToOne
private Artist artist;
#ManyToOne
private Genre genre;
When I submit the form, this is the error im getting:
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringOptionFieldAttrProcessor' (album/add:52)
The following code is part of my controller:
#RequestMapping({"/add", "/add/"})
public String adminAlbumAdd(Model model) {
model.addAttribute("album", new Album());
model.addAttribute("artists", artistService.list());
model.addAttribute("genres", genreService.list());
return "album/add";
}
#RequestMapping( value = "/save", method = RequestMethod.POST )
public String save(#Valid Album album, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors()) {
model.addAttribute("artists", artistService.list());
model.addAttribute("genres", genreService.list());
return "album/add";
} else {
Album savedAlbum = albumService.save(album);
return "redirect:/album/view/" + savedAlbum.getAlbumId();
}
}
And the following code is part of the thymeleaf template:
<div th:class="form-group" th:classappend="${#fields.hasErrors('artist')}? 'has-error'">
<label class="col-sm-2 control-label">Artist <span class="required">*</span></label>
<div class="col-md-10">
<select class="form-control" th:field="*{artist}">
<option value="">Select Artist</option>
<option th:each="artist : ${artists}" th:value="${artist.artistId}" th:text="${artist.artistFirstName + ' ' + artist.artistFirstName}">Artists</option>
</select>
<span th:if="${#fields.hasErrors('artist')}" th:errors="*{artist}" th:class="help-block">Artist Errors</span>
</div>
</div>
<div th:class="form-group" th:classappend="${#fields.hasErrors('genre')}? 'has-error'">
<label class="col-sm-2 control-label">Genre <span class="required">*</span></label>
<div class="col-md-10">
<select class="form-control" th:field="*{genre}">
<option value="">Select Genre</option>
<option th:each="genre : ${genres}" th:value="${genre.genreName}" th:text="${genre.genreName}">Genres</option>
</select>
<span th:if="${#fields.hasErrors('genre')}" th:errors="*{genre}" th:class="help-block">Genre Errors</span>
</div>
</div>
What is causing this error ?
The issue turned out to be related to the repository. I was extending CrudRepository, but the id was of type int. Once i changed that, it worked.
Firstly, you might consider using same mapping for GET/POST requests as a standard like:
#GetMapping("/new")
...
#PostMapping("/new")
Also #Valid Album album parameter should be annotated as #ModelAttribute.
You should not add model attributes if binding result has errors. (Actually, you should not add any model attribute for a POST method.)
You should not create that savedAlbum object with albumService.save().
That method should be void.
I will advise against posting directly to your database object. You should rather create a DTO class, say AlbumDto, that will map the classes like so:
public class AlbumDto {
...
private long genreId;
private long artistId;
// Getters & Setters
}
You can then convert it to your Album object, lookup the corresponding Genre and Artist in your controller, set them on the Album object and then save.

How do I iterate over all my model attributes on my JSP page?

I'm using Spring 3.2.11.RELEASE with JBoss 7.1.3.Final and Java 6. I have this method in a controller
#RequestMapping(value = "/method", method = RequestMethod.GET)
public String myMethod(final Model model,
final HttpServletRequest request,
final HttpServletResponse response,
final Principal principal)
...
model.addAttribute("paramName", "paramValue");
Notice how I add attributes into my model. My question is, on the JSP page that this page serves, how do I iterate over all the attributes in my model and output them as HIDDEN input fields with the name of the INPUT being the attribute name and the value being what I inserted in the model using that attribute?
Edit: In response to the answer given, here was the output to the JSP solution. Note there are no model attributes in there.
<input type='hidden' name='javax.servlet.jsp.jspRequest' value='org.springframework.web.context.support.ContextExposingHttpServletRequest#7a0a4c3f'>
<input type='hidden' name='javax.servlet.jsp.jspPageContext' value='org.apache.jasper.runtime.PageContextImpl#3939794a'>
<input type='hidden' name='appVersion' value='???application.version???'>
<input type='hidden' name='javax.servlet.jsp.jspResponse' value='org.owasp.csrfguard.http.InterceptRedirectResponse#722033be'>
<input type='hidden' name='javax.servlet.jsp.jspApplication' value='io.undertow.servlet.spec.ServletContextImpl#14c1252c'>
<input type='hidden' name='org.apache.taglibs.standard.jsp.ImplicitObjects' value='javax.servlet.jsp.el.ImplicitObjectELResolver$ImplicitObjects#23c27a49'>
<input type='hidden' name='javax.servlet.jsp.jspOut' value='org.apache.jasper.runtime.JspWriterImpl#b01a1ba'>
<input type='hidden' name='javax.servlet.jsp.jspPage' value='org.apache.jsp.WEB_002dINF.views.lti.launch_jsp#1dcc48bf'>
<input type='hidden' name='javax.servlet.jsp.jspConfig' value='io.undertow.servlet.spec.ServletConfigImpl#3fd40806'>
Model attributes are "request scope" objects
you can do the following (I use JSTL):
<c:forEach items="${requestScope}" var="par">
<c:if test="${par.key.indexOf('attrName_') > -1}">
<li>${par.key} - ${par.value}</li>
</c:if>
</c:forEach>
Since with no filter you will have all the request scope objects, I filtered by the model attributes we wanted to check
I tested by using this code:
#RequestMapping(method = { RequestMethod.GET }, value = { "/*" })
public String renderPage(Model model) throws Exception
{
String requestedUrl = req.getRequestURI();
int indice = requestedUrl.lastIndexOf('/');
String pagina = requestedUrl.substring(indice + 1);
try
{
String usernameUtente = "default username utente";
if (StringUtils.hasText(getPrincipal()))
{
usernameUtente = getPrincipal();
}
model.addAttribute("usernameUtente", usernameUtente);
model.addAttribute("webDebug", webDebug);
for(int i = 0; i<10; i++)
{
model.addAttribute("attrName_"+i, "attrValue_"+i);
}
return pagina;
}
catch (Exception e)
{
String message = "Errore nell'erogazione della pagina " + pagina;
logger.error(message, e);
return "genericError";
}
}
And this is what I see as output (I omitted the not relevant prints but please note you'll print ALL the request scope objects:
attrName_0 - attrValue_0
attrName_1 - attrValue_1
attrName_2 - attrValue_2
attrName_3 - attrValue_3
attrName_4 - attrValue_4
attrName_5 - attrValue_5
attrName_6 - attrValue_6
attrName_7 - attrValue_7
attrName_8 - attrValue_8
attrName_9 - attrValue_9
I hope this can help
Angelo
For avoid headache with parameters added by Spring and Servlet container, it is better to use separate map for pass values into the model. Just use #ModelAttribute and Spring will create and add it to the model automatically:
#RequestMapping(value = "/method", method = RequestMethod.GET)
public String myMethod(final Model model, #ModelAttribute("map") HashMap<String, Object> map) {
map.put("paramName1", "value1");
map.put("paramName2", "value2");
//...and so on
}
Now you can iterate this map in JSP:
<c:forEach items="${map.keySet()}" var="key">
<input type="hidden" name="${key}" value="${map[key]}"/>
</c:forEach>
Also you can access to every item of map next way:
<c:out value="${map.paramName1}"/>
<c:out value="${map.paramName2}"/>
...
If you don't need some parameter to be iterable, add it into the original ModelMap istead of separate map.
In essence all you need is to itterate on all the page attributes. Depending on what you use on your jsp (scriptlets, jstl, or smthing like thymeleaf for html):
Scriptlet:
<form>
<% Session session = request.getSession();
Enumeration attributeNames = session.getAttributeNames();
while (attributeNames.hasMoreElements()) {
String name = attributeNames.nextElement();
String value = session.getAttribute(name);
%>
<input type='hidden' name="<% name %>" value="<% value %>">
<%
}
%>
</form>
JSTL:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<h3>Page attributes:</h3>
<form>
<c:forEach items="${pageScope}" var="p">
<input type='hidden' name='${p.key}' value='${p.value}'>
</c:forEach>
</form>
Thymeleaf:
<form>
<input th:each="var : ${#vars}" type='hidden' name="${var.key}" value="${var.value}">
</form>
Simply you can iterate using foreach tag of Jstl.
<c:forEach items="${requestScope}" var="var">
<c:if test="${ !var.key.startsWith('javax.') && !var.key.startsWith('org.springframework')}">
<input type="hidden" name="${var.key}" value="${var.value}" />
</c:if>
</c:forEach>
Request attributes from spring framework and from Servlet do have prefixes, you don't need to add prefix to your request attributes.
Rather you can ignore all those attributes which have prefix "org.springframework" or "javax.".
You can try this:
#RequestMapping(value = "/method", method = RequestMethod.GET)
public String myMethod(final Model model,
final HttpServletRequest request,
final HttpServletResponse response,
final Principal principal)
...
//Create list for param names and another list for param values
List<String> paramNames = new ArrayList();
List<String> paramValues = new ArrayList();
paramNames.add("paramName1");
paramValues.add("paramValue1");
paramNames.add("paramName2");
paramValues.add("paramValue2");
//paramValue1 is the value corresponding to paramName1 and so on...
//add as many param names and values as you need
...
//Then add both lists to the model
model.addAttribute("paramNames", paramNames);
model.addAttribute("paramValues", paramValues);
Then in the JSP, you can iterate over paramNames list, and use the varStatus.index to get the index of current round of iteration and use it to pull the value of corresponding param value from the paramValues list. Like this -
<form id='f' name='myform' method='POST' action='/path/to/servlet'>
<c:forEach items="${paramNames}" var="paramName" varStatus="status">
<input type='hidden' name='${paramName}' value='${paramValues[status.index]}'>
</c:forEach>
</form>
You can add other input elements to the form as needed but the above should generate all the hidden input elements for each of your parameter that you set in the Model.

Format LocalDateTime with spring, jackson

In a spring rest application, i send a objet who contain a date
{ appointmentId: "", appointmentTypeId: "1", appointmentDate:
"2015-12-08T08:00:00-05:00" }
In my dto side
for my appointmentDate i have
#DateTimeFormat(iso=DateTimeFormat.ISO.DATE_TIME)
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime appointmentDate;
In my dependencies i have
jackson-datatype-jsr310-2.6.3
I get this error
rg.springframework.http.converter.HttpMessageNotReadableException:
Could not read document: Text '2015-12-08T13:00:00.000Z' could not be
parsed, unparsed text found at index 23 (through reference chain:
server.dto.AppointmentDto["appointmentDate"]); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Text
'2015-12-08T13:00:00.000Z' could not be parsed, unparsed text found at
index 23 (through reference chain:
server.dto.AppointmentDto["appointmentDate"])
tried only with DateTimeFormat, only with JsonDeserialize and both, but get the same error.
Edit
#RequestMapping(value = "/rest")
#RestController
public class LodgerController {
#RequestMapping(value = "/lodgers/{lodgerId}/appointments", method = RequestMethod.POST)
public Long createAppointmentsByLodgerId(#PathVariable("lodgerId") Long lodgerId, #RequestBody AppointmentDto appointmentDto) {
return appointmentService.save(appointmentDto);
}
}
public class AppointmentDto {
private Long appointmentId;
private Long appointmentTypeId;
private Long lodgerId;
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime appointmentDate;
public AppointmentDto() {
}
}
<form id="lodgerAppointmentForm" class="form-horizontal" role="form">
<input type="hidden" id="lodgerId" name="lodgerId">
<input type="hidden" id="lodgerAppointmentId" name="appointmentId">
<div class="form-group">
<label for="lodgerAppointmentDate" class="col-sm-2 control-label">Date</label>
<div class="col-sm-10">
<div class="input-group date" id="appointmentDatepicker" >
<input type="text" class="form-control" id="lodgerAppointmentDate" name="appointmentDate">
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar">
</span>
</span>
</div>
</div>
</div>
</form>
var locale = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage);
moment().locale(locale);
$('#appointmentDatepicker').datetimepicker({
format: 'DD/MM/YYYY H:mm',
allowInputToggle: true
});
var lodgerId = $('#lodgerId').val();
var type = "post";
var url = "http://localhost:8080/rest/lodgers/" + lodgerId + "/appointments";
var data = transForm.serialize('#lodgerAppointmentForm');
data.appointmentDate = $('#appointmentDatepicker').data('DateTimePicker').date().format();
data.lodgerId = lodgerId;
data = JSON.stringify(data);
jQuery.ajax({
type: type,
url: url,
contentType: "application/json",
data: data,
success: function (data, status, jqXHR) {
},
error: function (jqXHR, status) {
}
});
transform.js come from https://github.com/A1rPun/transForm.js/blob/master/src/transForm.js
bootstrap datetimepicker come from https://github.com/Eonasdan/bootstrap-datetimepicker
Moment use 2015-12-09T08:00:00-05:00 (ISO 8601)
DateTimeFormatter.ISO_LOCAL_DATE_TIME who is: 2015-12-09T08:00:00 (ISO 8601)
both don't seem to use the same format
I think that your problem is described here:
https://github.com/FasterXML/jackson-datatype-jsr310/issues/14
I encounter the same error when was playing around with LocalDateTime and REST API. The problem is that you can serialize LocalDateTime to something like this:
2015-12-27T16:59:29.959
And you can create valid Date object in JavaScript from that string.
On the other hand if you try to POST/PUT JavaScript date to server then this:
var myDate = new Date();
JSON.stringify(myDate);
will create string like this (with extra Z - which stands for zulu time/UTC time zone):
2015-12-27T16:59:29.959Z
And that extra time zone info causes error in your case during deserialization because LocalDateTime don`t have time zone.
You can try to use ZonedDateTime on ther server or format by yourself date string on client side before sending (without Z suffiks).

Resources