PainIsAMaster
PainIsAMaster

Reputation: 2076

using "Dozer" in Java to map String of date/time to java.sql.Timestamp and save in DB is writing time as 00:00:00.000000

I have a Spring Batch application (https://spring.io/projects/spring-batch) that reads comma delimited data from a .csv file and then maps each column to specific Java class beans, the saves it to a database (postgres). My problem is that one of the date/time columns, called END_DT is writing to the database with an incorrect time portion of the date/time. You can see the date part is correctly read (2023-04-15) but the time is just written as 00:00:00.000000

enter image description here

The steps it performs a little more in-depth are:

  1. Spring Batch app Reads in .CSV file which has multiple columns, the important one for this question is end_dt,
  2. From the end_dt column, a String in the format of dd-mmm-YYYY HH:mm:ss (i.e. 29-Apr-2099 23:59:59) is parsed out using this method:
private String getDateTimeString(String dateString) {

        SimpleDateFormat sdfTo = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
        SimpleDateFormat sdfFrom = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
        String formattedDateTimeStr = null;
       
            if (StringUtils.isNotEmpty(dateString)) {
                formattedDateTimeStr = sdfTo.format(sdfFrom.parse(dateString));
          }
        
        return formattedDateTimeStr;
}
  1. Then it takes this parse date/time String and saves it to the data class/Java Bean we'll call DaMasterRecord, holding all the column values from the excel (.csv) file
  2. Then using Dozer, these values from the data class DaMasterRecord are mapped to an Entity class that uses Hibernate/JPA which makes the String date/time to a java.sql.Timestamp data type, i.e.
@Entity
@Table(name = "blah_blah_blah", schema = "some_schema", catalog = "some_catalog")
// code inbetween

public class MyRandomClassEntity {
  private Timestamp endDt;

// more stuff
}

I know the date/time String is parsed correctly in the DaMasterRecord data class, because I can see it in the debugger. It's right after the Mapper interface method "mapper" is called in the Dozer framework that I see the wrong date/time listed in the Entity class via the debugger. So I'm not exactly sure how Dozer is doing it's mappings, but I'm guessing when Dozer goes to map the String that is "dd-mmm-YYYY HH:mm:ss" to a java.sql.Timestamp datatype, for some reason it doesn't map the "time" portion of the date/time String correctly (it just does 00:00:00.000000). Does anyone know how to fix this? There are a lot interfaces and overriden methods, so I haven't quite pinpointed where this mapping is happening.

Upvotes: 1

Views: 987

Answers (1)

PainIsAMaster
PainIsAMaster

Reputation: 2076

I was able to solve this issue and will post my answer here. I would also like to state this is a legacy application (not too old actually) but its using classes like "Timestamp" and "SimpleDateFormat" (pre-Java 8 API updates), so my intent was to solve this issue/bug/question with minimal effort and not having to re-write the application. Hopefully, this can be of use to any other developers who have a similar application/business issue.

  1. So I fist attempted to extend Dozer's DozerConverter<String, LocalDateTime> class to create my own custom converter for this String -> LocalDateTime object. However, I ran into issues with Dozer throwing exceptions trying to map the LocalDateTime object -> java.sql.Timestamp data type that our database column uses. We have another repo with all the database configurations, so again, I didn't want to have to go into that dependency and edit code (which could potentially break more components as they are dependent on it), so I trashed idea for the time.

When you use a custom converted like this, Dozer has an .xml (in your resources directory) file that you will have to attach this converter to the specific field you are trying to map, something like:

<field custom-converter="com.mydomainname.my.namespace.MyCustomConverter">
     <a>theColumnNameIamMappingFrom</a>
     <b>theColumnNameIamMappingTo</b>
</field>
  1. I also tried keeping the format of the DateTime String as "yyyy-MM-dd HH:mm:ss", which is the format of the Timestamp. However, everytime it mapped over to my database/Entity class, it always "cut" the time portion to 00:00:00.000000 for some reason.

  2. So last solution was a variation of the 1st, where I created a custom converter but this time had it convert to the java.sql.Timestamp data type. I was trying to avoid using these old legacy classes but other parts of the code seems too tightly-coupled to it and I didn't want to break everything. Anyway, it worked and I was finally able to see the DB save the timestamp as a full date and time i.e.

2020-08-31 23:59:59.123456

Hopefully this helps anyone else out if they have similiar issues. Dozer is kind of weird, but you can read more about it here: https://www.baeldung.com/dozer

Upvotes: 0

Related Questions