How to convert field in opencsv correct? - java

I have csv file with this columns id,equity_name,field,date,quartal,year. I have java class where there is a field
#Column(
columnDefinition = "smallint"
)
#Convert(
converter = YearAttributeConverter.class
)
#CsvCustomBindByName(column = "year", converter = YearCsvConverter.class)
private Year year;
And i use custom converter for this field.
#NoArgsConstructor
public class YearCsvConverter extends AbstractBeanField {
#Override
protected Object convert(String value) throws CsvDataTypeMismatchException, CsvConstraintViolationException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
return LocalDate.parse(value, formatter);
}
}
When i tried to parse file i have an
Exception in thread "pool-1-thread-6" java.lang.RuntimeException: com.opencsv.exceptions.CsvDataTypeMismatchException: Conversion of 1990-12-31 to java.time.LocalDate failed.
How to make this work and convert the field?

Your converter returns a LocalDate, but your field is of type Year, that is your DataTypeMismatch in the CsvDataTypeMismatchException.
Make your converter return an object of the correct data type e.g.:
return Year.fromLocalDate(LocalDate.parse(value, formatter));
On a side note: if you csvBindByName or CsvCustomBindByName, you don't need to specify the column name, and the following should work as long as your field name matches your header name.
#CsvCustomBindByName(converter = YearCsvConverter.class)
private Year year;

Related

Why univocity's CsvParser throwing error when use LocalDate as the datatype for POJO and How to reslove it?

I am using Univocity's CSVParser to read csv file. My POJO look something like this.
import java.time.LocalDate;
import com.univocity.parsers.annotations.NullString;
import com.univocity.parsers.annotations.Parsed;
import lombok.Builder;
import lombok.Getter;
#Getter
#Setter
public class TempClass {
#Parsed(field = "A")
private int a;
#Parsed(field = "B")
private String b;
#Parsed(field = "C")
private LocalDate c;
}
My csv file look something like this:-
A,B,C
1,"Hi","2019-01-12"
2,"Hey","2019-01-13"
3,"Hello","2019-01-14"
Now when I try to read this file using CsvParser, it throws error saying Unable to set value '2019-01-12' of type 'java.lang.String' to field attribute 'c'.
Here I am guessing it is throwing error because it can not implicitly convert String to LocalDate. If that is the case then How can it able to convert String to int?
Is there way to solve the error Unable to set value '2019-01-12' of type 'java.lang.String' to field attribute 'c'?(without changeing data type of TempClass.c)
Univocity-parsers is still built on Java 6. LocalDate is not directly supported out of the box, but can to provide a conversion yourself. Something like:
public class LocalDateFormatter implements Conversion<String, LocalDate> {
private DateTimeFormatter formatter;
public LocalDateFormatter(String... args) {
String pattern = "dd MM yyyy";
if(args.length > 0){
pattern = args[0];
}
this.formatter = DateTimeFormatter.ofPattern(pattern);
}
#Override
public LocalDate execute(String input) {
return LocalDate.parse(input, formatter);
}
#Override
public String revert(LocalDate input) {
return formatter.format(input);
}
}
Then annotate your fields with #Convert and provide your conversion class:"
#Parsed(field = "C")
#Convert(conversionClass = LocalDateFormatter.class, args = "yyyy-MM-dd")
private LocalDate c;
The next version (3.0.0) is coming soon with support for this and a lot more.
Hope this helps.

Failed to parse "Date" from JSON

I have the following JSON string in REST response:
"09:41:50 CET"
For the corresponding POJO mapper class has a Date type for this field. So I've tried Jackson and GSON to map JSON to Java Object, but both failed with the following messages:
GSON: java.text.ParseException: Failed to parse date ["09:41:50 CET"]: Invalid number: 09:4
Jackson: InvalidFormatException: Cannot deserialize value of type `java.util.Date` from
String "09:41:50 CET": not a valid representation
Sadly I cannot modify in the POJO class the type to string or anything else, because I get those POJO classes from mvn dependency.
Try with this:
public static void main(String[] args) throws ParseException {
String jsonStr = "{ \"date\" : \"09:41:50 CET\" }";
Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss").create();
JsonElement element = gson.fromJson (jsonStr, JsonElement.class);
OnlyDate date =gson.fromJson(element, new TypeToken<OnlyDate>(){}.getType());
System.out.println(date.getDate());
}
My example DTO is:
public class OnlyDate implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#SerializedName("date")
private Date date ;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
You have to specify the dateFormat of your gson Element
Not sure what kind of rest you have however if you are using spring rest you can do it by implementing custom Converter check the example at https://www.baeldung.com/spring-mvc-custom-data-binder.
Since Jackson v2.0, you can use #JsonFormat annotation directly on Object members;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss", timezone="CET")
private Date date;

Spring, parsing string to LocalDateTime

I've got model and field like this:
#Element(name = "TIMESTAMP")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime date;
In response I received:
<TIMESTAMP>2016-05-04T13:13:42.000</TIMESTAMP>
but during parsing xml to model I have error:
"message": "org.simpleframework.xml.core.PersistenceException: Constructor not matched for class java.time.LocalDateTime",
I also tried with:
#Element(name = "TIMESTAMP")
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime date;
and this still doesn't work. Any Idea ? I am using springframework.xml lib.
The problem is by default simplexml lib doesn't know how to serialize/deserialize new Java8 date types.
In order to succeed you need to use custom converter.
Example entity (see the special #Convert annotation)
public class Entity {
#Element(name = "TIMESTAMP")
#Convert(LocalDateTimeConverter.class)
private LocalDateTime date;
// omitted
}
Special converter
public class LocalDateTimeConverter implements Converter<LocalDateTime> {
public LocalDateTime read(InputNode node) throws Exception {
String name = node.getValue();
return LocalDateTime.parse(name, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
public void write(OutputNode node, LocalDateTime input) {
String value = input.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
node.setValue(value);
}
}
Usage
Strategy strategy = new AnnotationStrategy();
Persister persister = new Persister(strategy);
Entity serializedEntity = persister.read(Entity.class, xmlInputStream);
Full source is available on GitHub

#Type annotation in Hibernate is not Working. I am using #SQLInsert

I have a model class in hibernate with a field with Calendar type. The corresponding DB column is of timestampwithtimezone(6). I am using custom #SQLInsert. The class looks like below-
#Entity
#SQLInsert("insert into EMPLOYEE (STARTDATETIME) values (TO_TIMESTAMP_TZ(?,'DD- MM-YY HH.MI.SS PM TZHTZM '))" )
#Table(
name = "EMPLOYEE",
)
public class Employee {
#Column(
name = "STARTDATETIME",
nullable = false
)
#Type(type = "com.myPackage.TimeStampTypeImpl")
private Calendar startDateTime;
public Calendar getStartDateTime() {
return this.startDateTime;
}
public void setStartDateTime(Calendar startDateTime) {
this.startDateTime = startDateTime;
}
}
In the class TimeStampTypeImpl which is implementing Usertype is doing the necessary conversion of Calendar to suitable string which is supposed to be given in the input parameter of the insert query, in nullSafeSet method.
But the problem I am getting is- it seems that the the custome class TimestampImpl is not working- the nullSafeSet method is not getting called. So the insert query is failing.
The libraries I am using is-
hibernate-commons-annotations-4.0.1.Final-redhat-2.jar
hibernate-core-4.2.7.SP1-redhat-3.jar
hibernate-jpa-2.0-api-1.0.1.Final-redhat-2.jar
Code in TimeStampTypeImpl :
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
Calendar cal = (Calendar) value;
log.debug("TIMESTAMPIMPL2");
tring dateTime = getOracleFormattedTimeWithZone(cal);
log.debug("TIMESTAMPIMPL3");
st.setString(index, dateTime);
}
private static String getOracleFormattedTimeWithZone(Calendar timeWithZone) {
String dateFormat = "dd-MM-yy hh.mm.ss a Z";
DateFormat df = new SimpleDateFormat(dateFormat);
String dateTime = df.format(timeWithZone.getTime());
System.out.println("()()()()()()()()()"+dateTime);
return dateTime;
}

Play! framework bootstrap(Fixtures.loadModels("initial-data.yaml)), injecting "random" String value in model's setter

I have a model class with a persisted DateTime field that is only interacted via getters/setters for Transient properties, String date; and String time;. The do some very specific formatting to create the DateTime object that will be persisted or retrieved when need be.
The problem is that when my model's loaded from the yaml file, the setter for the time field receives a String value that doesn't correspond at all to anything in my project/code.
Here's the class with only relevant members:
package models;
import javax.persistence.*;
import org.hibernate.annotations.*;
import org.joda.time.*;
import org.joda.time.format.*;
import play.db.jpa.*;
#javax.persistence.Entity
public class Booking extends Model {
#Column
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
public DateTime datetime;
public Integer duration;
#Transient
public String date;
#Transient
public String time;
//default constructor called by play's model loader that sets default values that are required for the getters and setters to work.
public Booking() {
DateTimeFormatter fmt = DateTimeFormat.forPattern("'ISO8601':yyyy-MM-dd'T'HH:mm:ssZ");
this.datetime = fmt.parseDateTime("ISO8601:1970-01-01T00:00:00+0200");
//this.datetime = fmt.parseDateTime(this.date+"T"+this.time);
}
public void setDate(String dateStr) {
this.date = dateStr;
if (dateStr.contains("ISO")) {
DateTimeFormatter dt = DateTimeFormat.forPattern("'ISO8601':yyyy-MM-dd'T'HH:mm:ssZ");
DateTime tmp = dt.parseDateTime(dateStr);
this.datetime = toDateTime(tmp.toString("yyyy-MM-dd"), getTime());
} else {
this.datetime = toDateTime(dateStr, getTime());
}
}
public void setTime(String timeStr) {
this.time = timeStr; //timeStr = "780" for some reason?!
if (timeStr.contains("ISO")) {
DateTimeFormatter dt = DateTimeFormat.forPattern("'ISO8601':yyyy-MM-dd'T'HH:mm:ssZ");
DateTime tmp = dt.parseDateTime(timeStr);
this.datetime = toDateTime(getDate(), tmp.toString("HH:mm"));
}
this.datetime = toDateTime(getDate(), timeStr);
}
public String getDate() {
DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd");
return this.datetime.toString(format);
}
public String getTime() {
DateTimeFormatter format = DateTimeFormat.forPattern("HH:mm");
return this.datetime.toString(format);
}
private DateTime toDateTime(String dateStr, String timeStr) {
DateTimeFormatter fmt = ISODateTimeFormat.dateHourMinute();
DateTime dt = fmt.parseDateTime(dateStr + "T" + timeStr);
return dt;
}
When I run through the debugger, the timeStr parameter that setTime receives when it's first called is "780". There is no such value in my yaml file as the model is injected like this:
Booking(bobBooking):
date: 2011-09-16
time: 13:00
duration: 30
headcount: 10
room: b
user: bob
description: Bob's Booking.
The additional fields are omitted.
Try using quotes for time value in yaml file. There could be some issue in parsing colon fields using SnakeYAML parser (which is the default in Play)
YAML 1.1 defines 13:00 as a sexagesimal value (which is not what you expect)
http://yaml.org/type/int.html
Use single or double quotes to specify a string value. ('13:00', "13:00")

Categories