Java:如何移除Hibernate实体getById方法中的Class参数
解决方案
要实现Home.getById(1)这种无需传入Home.class的调用方式,有两种靠谱的实现思路:
方案一:子类封装静态调用(最简单直接)
不需要修改父类的原有逻辑,只需要在每个实体类里添加一个静态方法,把Home.class的传入逻辑封装起来:
public class Home extends BaseDatabaseEntity { @Id private long id; // 新增子类专属的静态getById方法 public static Home getById(Serializable id) { // 直接调用父类方法,预先传入当前类的Class对象 return BaseDatabaseEntity.getById(Home.class, id); } }
之后调用就可以直接写:
Home.getById(1);
这种方式的优点是:对原有代码侵入极小,逻辑简单清晰,不会引入反射相关的潜在问题。
方案二:利用泛型父类实现实例方法调用
如果不想每个子类都写重复的静态方法,可以把父类改成泛型抽象类,借助"循环泛型"的特性来自动获取子类的Class对象,不过此时方法会变成实例方法:
第一步:修改父类为泛型类
public abstract class BaseDatabaseEntity<T extends BaseDatabaseEntity<T>> { public T getById(Serializable id) { Transaction transaction = null; try { @Cleanup Session session = HibernateConfigurator.getSessionFactory().openSession(); transaction = session.beginTransaction(); // 通过反射获取泛型参数对应的子类Class Class<T> clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; T returner = session.get(clazz, id); transaction.commit(); return returner; } catch (Exception e) { // 别忘了回滚事务并处理异常 if (transaction != null) { transaction.rollback(); } throw new RuntimeException("获取实体失败", e); } } }
第二步:子类继承时指定自身为泛型参数
public class Home extends BaseDatabaseEntity<Home> { @Id private long id; }
调用方式
此时需要通过实体类的实例来调用方法:
new Home().getById(1);
这种方式的优点是不用在每个子类写重复代码,但缺点是需要创建实例(不过对于Hibernate实体来说,空实例的创建成本极低),且引入了反射逻辑,若子类存在多层继承,泛型反射的逻辑需要调整(比如递归获取父类的泛型参数)。
内容的提问来源于stack exchange,提问作者Crafter_Y
相关产品推荐
相关产品推荐

