Replace the Temporal annotation with a Converter annotation for some java.sql attributes

OpenJPA persists the fields of attributes of type java.sql.Date, java.sql.Time, or java.sql.Timestamp that have a javax.persistence.Temporal annotation, whereas EclipseLink throws an exception.

For some combinations of the javax.persistence.Temporal annotation and the java.sql.Date, java.sql.Time, and java.sql.Timestamp attributes, you must add converter code so that EclipseLink is compatible with the tables that were created by OpenJPA.

This rule scans for three annotation-attribute combinations where a converter class is needed to transform the data between the database and the entity:

For cases where no conversion is needed and the Temporal annotation can be removed, see the Remove Temporal annotation for some java.sql attributes rule.

@Temporal(TemporalType.TIMESTAMP) on a java.sql.Date attribute

In this case, the rule flags the Temporal(TemporalType.TIMESTAMP) annotation.

   @javax.persistence.Temporal(TemporalType.TIMESTAMP)
   private java.sql.Date date;

To resolve this issue, create a common converter utility class that can be used for all attributes that need this converter:

  1. Create a Converter class that converts a date to a time stamp, such as the following example.
    import java.sql.Date;
    import java.sql.Timestamp;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    
    @Converter
    public class DateTimestampConverter implements AttributeConverter<Date, Timestamp> {
        @Override
        public Timestamp convertToDatabaseColumn(Date date) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MILLISECOND, 0);
            return new Timestamp(cal.getTime().getTime());
        }
    
        @Override
        public Date convertToEntityAttribute(Timestamp timestamp) {
            return new Date(timestamp.getTime());
        }
    }
    
  2. Add the converter class to the persistence unit definition.
  3. Replace the Temporal(TemporalType.TIMESTAMP) annotation on the java.sql.Date attribute with a Convert annotation that has the converter attribute set to the new converter class.

    The following example shows the original Temporal(TemporalType.TIMESTAMP) annotation:

    import javax.persistence.Convert;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Temporal(TemporalType.TIMESTAMP)
        private java.sql.Date sqlDateTIMESTAMP;
    }
    

    The following example shows the new Convert annotation:

    import javax.persistence.Convert;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Convert(converter=DateTimestampConverter.class)
        private java.sql.Date sqlDateTIMESTAMP;
    }
    

@Temporal(TemporalType.DATE) on a java.sql.Timestamp attribute

In this case, the rule flags the Temporal(TemporalType.DATE) annotation.

   @javax.persistence.Temporal(TemporalType.DATE)
   private java.sql.Timestamp timestamp;

To resolve this issue, create a common converter utility class that can be used for all attributes needing this converter:

  1. Create a Converter class that converts a time stamp to a date, such as the following example.
    import java.sql.Date;
    import java.sql.Timestamp;
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    
    @Converter
    public class TimestampDateAnnConverter implements AttributeConverter<Timestamp, Date>{
        @Override
        public Date convertToDatabaseColumn(Timestamp ts) {
            return new Date(ts.getTime());
        }
    
        @Override
        public Timestamp convertToEntityAttribute(Date date) {
            return new Timestamp(date.getTime());
        }
    }
    
  2. Add the converter class to the persistence unit definition.
  3. Replace the Temporal(TemporalType.DATE) annotation on the java.sql.Timestamp attribute with a Convert annotation that has the converter attribute set to the new converter class.

    The following example shows the original Temporal(TemporalType.DATE) annotation:

    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Temporal(TemporalType.DATE)
        private java.sql.Timestamp sqlTimestampDate;
    }
    

    The following example shows the new Convert annotation:

    import javax.persistence.Convert;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Convert(converter=TimestampDateAnnConverter.class)
        private java.sql.Timestamp sqlTimestampDate;
    }
    

@Temporal(TemporalType.TIME) on a java.sql.Timestamp attribute

In this case, the rule flags the Temporal(TemporalType.TIME) annotation.

   @javax.persistence.Temporal(TemporalType.TIME)
   private java.sql.Timestamp timestamp;

To resolve this issue, create a common converter utility class that can be used for all attributes needing this converter:

  1. Create a Converter class that converts a time stamp to a time such as the following example.
    import java.sql.Time;
    import java.sql.Timestamp;
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    
    @Converter
    public class TimestampTimeAnnConverter implements AttributeConverter<Timestamp, Time>{
        @Override
        public Time convertToDatabaseColumn(Timestamp ts) {
            return new Time(ts.getTime());
        }
    
        @Override
        public Timestamp convertToEntityAttribute(Time time) {
            return new Timestamp(time.getTime());
        }
    }
    
  2. Add the converter class to the persistence unit definition.
  3. Replace the Temporal(TemporalType.TIME) annotation on the java.sql.Timestamp attribute with a Convert annotation that has the converter attribute set to the new converter class.

    The following example shows the original Temporal(TemporalType.TIME) annotation:

    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Temporal(TemporalType.TIME)
        private java.sql.Timestamp sqlTimestampTime;
    }
    

    The following example shows the new Convert annotation:

    import javax.persistence.Convert;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    
    @Entity
    public class TemporalEntityOJ {
        @Id
        private int id;
        @Convert(converter=TimestampTimeAnnConverter.class)
        private java.sql.Timestamp sqlTimestampTime;
    }
    

For information about this issue and other OpenJPA to EclipseLink migration issues, see the OpenJPA to EclipseLink JPA Migration: Mappings guide.