how to get valid Date and Time instances using spring and thymeleaf - java

i am using thymeleaf and spring boot in my project and i need to save date and
time object in mySql database, this is how i have validated my entity class
#NotNull
#Column(name = "sdate")
#DateTimeFormat(iso = ISO.DATE)
private Date sdate; //represents start Date - i am passing 2014-01-01- this works fine.
#NotNull
#Column(name = "stime")
#DateTimeFormat(iso = ISO.TIME)
private Date stime; //represent start time - i am passing 12:10:20.444
when i am trying to get the values from thymleaf form to the controller i cant get a valid class it contain errors. is there something i am doing wrong with the validation part. how can i get a valid input from the form.
public String save(#ModelAttribute("travel") #Valid Travel travel,BindingResult result){
if (result.hasErrors()) {
for (Object element : result.getAllErrors()) {
System.out.println(element.toString());
}
}
error message :
Field error in object 'travel' on field 'stime': rejected value [12:10:20.444]

According to spring document for DateTimeFormat.ISO.TIME, the right format for ISO.TIME is "12:10:20.444+00:00", where the "+00:00" part is the time zone offset (suppose that there is no offset for your time zone).
So you need to reformat your input to include the time zone offset in your time string.

Related

Codec not found for requested operation: [TEXT <-> java.time.LocalDate]

This is the code which I am using to fill the column in the db.
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
JSONObject publishedObj = jsonObject.optJSONObject("created");
if(publishedObj != null){
String dateStr = publishedObj.getString("value");
book.setPublishedDate(LocalDate.parse(dateStr,dateFormat));
}
Below is the instance variable of the column where the data needs to go:
#Column("published_date")
#CassandraType(type = CassandraType.Name.DATE)
private LocalDate publishedDate;
Error Message which i am getting:
com.datastax.oss.driver.api.core.type.codec.CodecNotFoundException: Codec not found for requested operation: [TEXT <-> java.time.LocalDate]
Can please someone help.
Thankyou!!
I can reproduce that error with your code above. To remedy it, I have ALTERed the book_by_id table with two new columns:
ALTER TABLE book_by_id ADD pubdate2 TEXT;
ALTER TABLE book_by_id ADD pubdate3 DATE;
My BookEntity class for those columns looks like this:
#Column("pubdate2")
#CassandraType(type = CassandraType.Name.TEXT)
private String publishedDate2;
#Column("pubdate3")
#CassandraType(type = CassandraType.Name.DATE)
private LocalDate publishedDate3;
The code to parse and set the date looks like this:
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
String dateStr = "2022-03-03T09:52:33.235555";
musicBook.setPublishedDate2(LocalDate.parse(dateStr,dateFormat).toString());
musicBook.setPublishedDate3(LocalDate.parse(dateStr,dateFormat));
template.insert(musicBook);
tl;dr;
Redefine published_date as a DATE type, and it will work. Besides, dates/times should be stored in date/time types in databases.
Note that Cassandra won't allow you to modify a column's data type. Also, the process of dropping and adding a column with the same name in quick succession has proven to be problematic with Cassandra in the past. I'd advise adding a newly named column of a DATE type, and reloading its data. Or recreate the table (with the correct data types) and reload the data.

typeMismatch.target spring boot batch rejected value [2020-09-18T00:00:00+02:00]

I am trying to integrate data from CSV file with spring boot using a batch,
I have a problem with the date field because it is constantly rejected regardless of the type used,
here is my code:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String service;
private Timestamp time;
#Override
public IndProd process(final IndProd indProd) throws Exception {
String service = indProd.getService();
Timestamp time = indProd.getTime();
Long nbAppels = indProd.getNbAppels();
Integer tempsDeReponseMoyenMillisecondes = indProd.getTempsDeReponseMoyenMillisecondes();
Long volume = indProd.getVolume();
BigDecimal tempsDeReponseMoyenSecondes = indProd.getTempsDeReponseMoyenSecondes();
IndProd transformedIndProd = new IndProd(service,time,nbAppels,tempsDeReponseMoyenMillisecondes,volume,tempsDeReponseMoyenSecondes);
return transformedIndProd;
}
here is the error returned:
Caused by: org.springframework.validation.BindException:
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'target' on field 'time': rejected value
[2020-09-18T00:00:00+02:00]; codes
[typeMismatch.target.time,typeMismatch.time,typeMismatch.java.sql.Timestamp,typeMismatch];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [target.time,time]; arguments []; default message [time]];
default message [Failed to convert property value of type
'java.lang.String' to required type 'java.sql.Timestamp' for property
'time'; nested exception is java.lang.IllegalStateException: Cannot
convert value of type 'java.lang.String' to required type
'java.sql.Timestamp' for property 'time': no matching editors or
conversion strategy found] at
org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper.mapFieldSet(BeanWrapperFieldSetMapper.java:201)
~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE] at
org.springframework.batch.item.file.mapping.DefaultLineMapper.mapLine(DefaultLineMapper.java:43)
~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE] at
org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:185)
~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE] ... 56
common frames omitted
Thanks for your help
From the error, it clear that indProd.getTime() returns a String value which you are trying to assign to a Timestamp variable. Assuming indProd.getTime() returns a date-time string in the format, yyyy-MM-dd'T'HH:mm:ssXXX e.g. 2020-09-18T00:00:00+02:00 (as mentioned in the title of your question), you should replace
Timestamp time = indProd.getTime();
with
Timestamp time = new Timestamp(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse(indProd.getTime()).getTime());
Note: java.sql.Timestamp extends java.util.Date and the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API.
Using the modern date-time API:
OffsetDateTime odt = OffsetDateTime.parse(indProd.getTime());
//...
IndProd transformedIndProd = new IndProd(service,odt,nbAppels,tempsDeReponseMoyenMillisecondes,volume,tempsDeReponseMoyenSecondes);
and declare the instance members as
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String service;
private OffsetDateTime odt;// Change the type to OffsetDateTime
Learn more about the modern date-time API at Trail: Date Time. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
As the error said you are trying to assign a String value to an Instant variable.
That mean indProd.getTime() is trying to be String.
One way to fix this is to retype to String back to instant, it is maybe not the best solution but is should work.
Timestamp time = Timestamp.from(ZonedDateTime.parse(indProd.getTime()).toInstant());
and in IndProd variable change time to String

Timezone of ZonedDateTime changed to UTC during auto conversion of RequestBody with Spring Boot

I'm trying to keep ZoneId of ZonedDateTime which is set on front-end while performing POST/PUT to Spring Boot controller.
The value I want to transfer is:
2019-05-01T00:00:00+01:00[Europe/Zagreb]
After POST/PUT the ZoneId is converted to UTC and hours are adjusted. Technically this updated value represents the same point on time line, but the original ZoneId is lost and I would like to have it stored to be able to show it back later to end user.
// DTO
public class PriceInfoDTO {
#JsonFormat( pattern = "yyyy-MM-dd'T'HH:mm:ssXXX['['VV']']",
with = JsonFormat.Feature.WRITE_DATES_WITH_ZONE_ID )
#DateTimeFormat( pattern = "yyyy-MM-dd'T'HH:mm:ssXXX['['VV']']", iso = ISO.DATE_TIME )
private ZonedDateTime validFrom;
}
// Controller
#PutMapping(
path = PATH + "/{id}",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<PriceInfo> update(
#PathVariable("id") final Integer id,
#RequestBody final PriceInfoDTO dto
) {
System.out.println(dto);
...
}
Looking at Network tab in my browser, the request from browser to Spring Controller has this value (payload):
2019-05-01T00:00:00+01:00[Europe/Zagreb]
which is the same as format pattern.
When I dump DTO to console, I get this result:
2019-04-30T22:00Z[UTC]
Is there any way to preserve ZoneId as it was received in a request? Should I write my own Serializer and Deserializer to achieve this?
Thanks!
Add the following line to the application.properties file:
spring.jackson.deserialization.ADJUST_DATES_TO_CONTEXT_TIME_ZONE = false
References:
Baeldung: Jackson Date: Deserialize Joda ZonedDateTime with Time Zone Preserved
Javadoc: jackson-databind 2.6.0 API: ADJUST_DATES_TO_CONTEXT_TIME_ZONE
Spring Boot: “How-to” Guides: Customize the Jackson ObjectMapper
Can also be set programmatically with ObjectMapper :
objectMapper.configure(SerializationFeature.WRITE_DATES_WITH_ZONE_ID, true);
objectMapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

How to insert date in mongo db from java

There are many similar questions asked. But not exactly similar to the issue i am facing. I have seen almost all the questions and answers around it
So the problem is
I got to insert a date field in my mongo collection
But I can't access the collection directly. I got to use a service. The service takes a string and returns me oid.
So once i construct the BasicDBObject I call toString on it and pass it on to my service.. I even tried inserting it directly in a test collection and mongo is complaining.
BasicDBObject document = new BasicDBObject();
long createdAtSinceEpoch = 0;
long expiresAtSinceEpoch = 0;
createdAtSinceEpoch = System.nanoTime();
Date createdAt = new Date(TimeUnit.NANOSECONDS.toMillis(createdAtSinceEpoch));
document.append("createdAt", createdAt);
expiresAtSinceEpoch = createdAtSinceEpoch + +TimeUnit.SECONDS.toNanos(30);
Date expiresAt = new Date(TimeUnit.NANOSECONDS.toMillis(expiresAtSinceEpoch));
document.append("expiresAt", expiresAt);
service.storeRecord(document.toString());
and the generated JSON String looks like
{
"createdAt": {
"$date": "2015-09-01T20:05:21.641Z"
},
"expiresAt": {
"$date": "2015-09-01T20:05:51.641Z"
}
and Mongo complains that
Unable to parse JSON : Date expecting integer milliseconds, at (3,17)
So If i pass milliseconds alone instead of date object in the document.append() method then it DOES NOT recognize this field as date and considers it as String but inserts into the collection
I need 2 things
1) I want the data to be inserted
2) I am planning to expire that row by adding an index to the expiresAt field. So I want mongo to recognize that its a date field
JSON makes a difference between a numeric field and a text field containing a number. The latter one is only recognized as a String; I assume that this is what you did when you thought you were giving your service the date as an integer. Unfortunately you didn’t show us the relevant code.
When I save the Date info as a non String format, I annotate the field in my DTO as below. This helps the MongoDB know that the field is to be treated as an ISO date which then would be useful for making range search etc.,
#DateTimeFormat(iso = ISO.DATE_TIME) private Date date;
Date date = new Date();
BasicDBObject date= new BasicDBObject("date", date);
Data.insert(date);

how to map java.util.Date to MySql Date in Ibatis when I take input through JSON

I am taking date of birth as input using JSON
{"dateOfBirth":"1973-08-26"}
This field exists in Person.java class
import java.util.Date;
public class Person {
Date dateOfBirth;
//Some other fields
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
}
This is mapped to person table in mysql database.
I am querying the database like:
entityId = (Long) session.selectOne("ValidatePerson", registerUserRequestParams);
Following are the entries I am making in my mapper.xml
<select id="ValidatePerson" parameterMap="ValidatePersonMap" resultType="long">
select person.entityId
from person
where
//Some other Validation checks
<if test="dateOfBirth != null">
and person.dateOfBirth = #{dateOfBirth}
</if>
);
</select>
I have a prameter Map as
<parameterMap id="ValidatePersonMap" type="java.util.HashMap">
<parameter property="dateOfBirth" javaType="java.util.Date" jdbcType="DATE" mode="IN"/>
</parameterMap>
I am not able to get any result from database.It does not select any row even though value exists.I have checked that none of other validation checks are failing. If I pass dateOfBirth as null in JSON then then I get result.
I have also written a test case and setting request as follows:
Date dob = new Date(73,7,26);
request.setDateOfBirth(dob);
When I pass values from test case as mentioned above I get result from database.
Problem occurs only when i get request parameters using json.
The format of JSOn and the format stored in DB are same
One work around I have is to manually convert java.util.Date to String in above format and pass it as string. But this is pretty bad approach and client would not like it.
Use Timestamp. Consider Joda time plug. ...and read this answer.
These three will absolutely do the magic.
Good luck!
Have you tried formatting the java date. Maybe the formats are different so it can't match between the JSON and the one stored in your db?
This worked for me:
mysql attribute type is Timestamp
and I format the date for JSON in Java like this:
Date d = new Date();
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
String sd = sdf.format(d);
java.text.SimpleDateFormat sdf2 = new java.text.SimpleDateFormat("HH:MM:ss");
String fakeit =sd+"T"+sdf2.format(d);
I then use fakeit

Categories

Resources