Reputation: 10400
OpenJPA3.2.2 supports AttributeConverter
but I always get a cast error.
class java.lang.String cannot be cast to class java.util.Calendar (java.lang.String and java.util.Calendar are in module java.base of loader 'bootstrap')
I hava tried String, java.sql.Timestamp, java.util.Date
"db type" but OpenJPA gives a cast error. What is the type I should use for Mysql DATETIME in an attribute converter?
Java bean must use Calendar
field for legacy reason, this is an old codebase used by several apps. If not using @Convert
annotation in a field then calendar is saved to a database, but I need to force calendar value to a utc timezoned yyyy-MM-dd HH:mm:ss
.
@Entity @Table(name="service") @Access(AccessType.FIELD)
public class Service {
...
@Column(nullable=false)
@Convert(converter=JPAConverter.class)
private Calendar updated;
}
CREATE TABLE IF NOT EXISTS service (
id bigint UNSIGNED NOT NULL default '0',
updated datetime NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
@Converter(autoApply=false)
public class JPAConverter implements AttributeConverter<Calendar, String> {
@Override
public String convertToDatabaseColumn(Calendar val) {
if(val==null) return null;
return DateUtil.formatDateTime(val, DateUtil.TIMEZONE_UTC);
}
@Override
public Calendar convertToEntityAttribute(String dbVal) {
if(dbVal==null) return null;
return DateUtil.parseDateTimeFromUTC(dbVal);
}
}
Stackrace is
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.Calendar (java.lang.String and java.util.Calendar are in module java.base of loader 'bootstrap')
at org.apache.openjpa.jdbc.sql.DBDictionary.setTyped(DBDictionary.java:1551)
at org.apache.openjpa.jdbc.sql.RowImpl.flush(RowImpl.java:1002)
at org.apache.openjpa.jdbc.sql.RowImpl.flush(RowImpl.java:962)
at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushAndUpdate(PreparedStatementManagerImpl.java:119)
at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushAndUpdate(BatchingPreparedStatementManagerImpl.java:80)
at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushInternal(PreparedStatementManagerImpl.java:102)
at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flush(PreparedStatementManagerImpl.java:90)
at org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:555)
at org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:109)
at org.apache.openjpa.jdbc.kernel.BatchingConstraintUpdateManager.flush(BatchingConstraintUpdateManager.java:61)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:109)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:81)
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:755)
at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:146)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2310)
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2201)
at org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:2118)
... 55 more
Upvotes: 0
Views: 56
Reputation: 10400
I had to give up with AttributeConverter
and use an openjpa specific functions. Maybe things worked better with OpenJPA4.x library but I don't want to do javax.* to jakarta.*
package name change now.
import org.apache.openjpa.persistence.Externalizer;
import org.apache.openjpa.persistence.Factory;
@Factory("JPAUtil.db2calendar") // utc-to-calendar
@Externalizer("JPAUtil.calendar2db")
@Column(nullable=false) @Temporal(TemporalType.TIMESTAMP)
private Calendar created;
public class JPAUtil {
private static DateTimeFormatter calFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);
public static String calendar2db(Calendar val, StoreContext ctx) {
if(val==null) return null;
return calFormat.format(val.toInstant());
}
public static Calendar db2calendar(String val, StoreContext ctx) {
if(val==null) return null;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis( Instant.from(calFormat.parse(val)).toEpochMilli() );
return cal;
}
}
Upvotes: 0