情况 :
我有一个具有java.util.Date类型变量的可持久类:
import java.util.Date; @Entity @Table(name = "prd_period") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public class Period extends ManagedEntity implements Interval { @Column(name = "startdate_", nullable = false) private Date startDate; }
DB中的对应表:
CREATE TABLE 'prd_period' ( 'id_' bigint(20) NOT NULL AUTO_INCREMENT, ... 'startdate_' datetime NOT NULL )
然后,将我的Period对象保存到DB:
Period p = new Period(); Date d = new Date(); p.setStartDate(); myDao.save(p);
之后,如果我尝试从数据库中提取对象,则使用时间戳记类型的变量startDate返回该对象-我尝试使用equals(…)的所有位置均返回false。
问题 :是否有任何方法可以强制Hibernate以java.util.Date类型的对象(而不是Timestamp)的形式返回日期,而无需显式修改每个此类变量(例如,它必须能够正常工作,而无需显式修改java.util的现有变量日期类型)?
注意:
我发现了许多显式解决方案,其中使用了批注或修改了setter,但是我有很多带有Date-variables的类- 因此,我需要一些集中式解决方案,而下面描述的所有内容还不够好:
@Column @Type(type="date") private Date startDate;
@Temporal(TemporalType.DATE) @Column(name=”CREATION_DATE”) private Date startDate;
public void setStartDate(Date startDate) { if (startDate != null) { this.startDate = new Date(startDate.getTime()); } else { this.startDate = null; } }
此处提供了详细信息:http : //blogs.sourceallies.com/2012/02/hibernate-date-vs- timestamp/
因此,我花了一些时间解决这个问题,并找到了解决方案。它不是一个漂亮的东西,但至少是一个起点-也许有人会用一些有用的注释来补充它。
我在处理中发现的一些有关映射的信息:
private static final Map BASIC_TYPES; ... basics.put( java.util.Date.class.getName(), Hibernate.TIMESTAMP ); ... BASIC_TYPES = Collections.unmodifiableMap( basics );
如您所见,java.util.Date类型与Hibernate类型org.hibernate.type.TimestampType相关联
Iterator clsMappings = cfg.getClassMappings(); while(clsMappings.hasNext()){ PersistentClass mapping = (PersistentClass) clsMappings.next(); handleProperties(mapping.getPropertyIterator(), map); }
Type result = TypeFactory.heuristicType(typeName, typeParameters);
至此,我了解到我无法修改BASIC_TYPES(这是唯一的方法),无法将SimpleValue对象替换为java.util.Date类型的属性,更改为我的自定义对象,从而可以知道要转换的确切类型。
解决方案:
public class HibernatePersistenceExtensions extends HibernatePersistence { @Override public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) { if ("true".equals(map.get("hibernate.use.custom.entity.manager.factory"))) { return CustomeEntityManagerFactoryFactory.createCustomEntityManagerFactory(info, map); } else { return super.createContainerEntityManagerFactory(info, map); } } }
public class ReattachingEntityManagerFactoryFactory { @SuppressWarnings("rawtypes") public static EntityManagerFactory createContainerEntityManagerFactory( PersistenceUnitInfo info, Map map) { Ejb3Configuration cfg = new Ejb3Configuration(); Ejb3Configuration configured = cfg.configure( info, map ); handleClassMappings(cfg, map); return configured != null ? configured.buildEntityManagerFactory() : null; } @SuppressWarnings("rawtypes") private static void handleClassMappings(Ejb3Configuration cfg, Map map) { Iterator clsMappings = cfg.getClassMappings(); while(clsMappings.hasNext()){ PersistentClass mapping = (PersistentClass) clsMappings.next(); handleProperties(mapping.getPropertyIterator(), map); } } private static void handleProperties(Iterator props, Map map) { while(props.hasNext()){ Property prop = (Property) props.next(); Value value = prop.getValue(); if (value instanceof Component) { Component c = (Component) value; handleProperties(c.getPropertyIterator(), map); } else { handleReturnUtilDateInsteadOfTimestamp(prop, map); } } private static void handleReturnUtilDateInsteadOfTimestamp(Property prop, Map map) { if ("true".equals(map.get("hibernate.return.date.instead.of.timestamp"))) { Value value = prop.getValue(); if (value instanceof SimpleValue) { SimpleValue simpleValue = (SimpleValue) value; String typeName = simpleValue.getTypeName(); if ("java.util.Date".equals(typeName)) { UtilDateSimpleValue udsv = new UtilDateSimpleValue(simpleValue); prop.setValue(udsv); } } } } }
如您所见,我只是遍历每个属性,并用SimpleValue-object替换UtilDateSimpleValue来替换类型java.util.Date的属性。这是一个非常简单的类-它实现与SimpleValue对象相同的接口,例如org.hibernate.mapping.KeyValue。在构造函数中,将传递原始SimpleValue对象- 因此,每次调用UtilDateSimpleValue都会被重定向到原始对象,但有一个异常-方法getType(…)返回我的自定义类型。
public class UtilDateSimpleValue implements KeyValue{ private SimpleValue value; public UtilDateSimpleValue(SimpleValue value) { this.value = value; } public SimpleValue getValue() { return value; } @Override public int getColumnSpan() { return value.getColumnSpan(); } ... @Override public Type getType() throws MappingException { final String typeName = value.getTypeName(); if (typeName == null) { throw new MappingException("No type name"); } Type result = new UtilDateUserType(); return result; } ... }
public class UtilDateUserType extends TimestampType{ @Override public Object get(ResultSet rs, String name) throws SQLException { Timestamp ts = rs.getTimestamp(name); Date result = null; if(ts != null){ result = new Date(ts.getTime()); } return result; } }
就这些。有点棘手,但是现在每个java.util.Date属性都作为java.util.Date返回,而无需对现有代码进行任何其他修改(注释或修改setter)。