OpenJPA3.2.2 支持
AttributeConverter
但我总是遇到强制转换错误。
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')
我尝试了
String, java.sql.Timestamp, java.util.Date
“db type”,但 OpenJPA 给出了强制转换错误。我应该在属性转换器中为 Mysql DATETIME 使用什么类型?
由于遗留原因,Java bean 必须使用 Calendar
字段,这是多个应用程序使用的旧代码库。如果不在字段中使用
@Convert
注释,则日历将保存到数据库中,但我需要将日历值强制为 utc 时区
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 是
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
AttributeConverter
并使用openjpa特定功能。也许使用 OpenJPA4.x 库效果更好,但我现在不想更改
javax.* to jakarta.*
包名称。
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;
}
}