在使用 jpa 的 jax-rs 休息服务中使用泛型的障碍

Roadblock using generics in jax-rs rest services using jpa

我正在编写一个公开关系数据库的休息服务。我在应用程序中有三层:

  1. 持久层(JPA 实体)
  2. EJB 层
  3. 休息层

对于每个实体,我正在实施的方法是:addupdatefindAllfindById。我在 Rest 层EJB 层 中都使用了 Java 泛型,以便编写尽可能少的代码。

但是我在实现方法 findByIdEJB 层 遇到了障碍,因为数据库的一些实体有一个 Integer 类型的主键,其他人有一个 String 类型的主键。通用EJB实现如下:

public abstract class SimpleEJB <T extends Object> {

    //This entity is injected by the container.
    @PersistenceContext(name="PersistenceUnit")
    private EntityManager em;

    private Class<?> TClass;

    public SimpleEJB(Class<?> entityClass){
        this.TClass = entityClass;
    }

    public T findById(String id){
        T t = this.em.find(this.TClass, id);
        return t;
    }
}

我不想为我可能找到的每个不同的主键类型(整数、字符串、日期等)编写摘要 类(在 rest 层和 ejb 层上)。由于其余层接收主键作为 url 中的 String,我是否可以将 String 传递给 EJB 层,并将 find 方法 [=21] =] 自动将 String 转换为 T 的类型,还是我被迫为每个不同的主键类型编写不同的摘要 类?

旁注:我无法更改数据库。

我认为您可以对 TClass 做一些反思以获得 id 字段的类型(假设这是 "id" 字段的通用名称)和只是有条件地设置 PK 为 check 。像

public T findById(String id) throws Exception {
    Field idField = TClass.getDeclaredField("id");
    Class<?> type = idField.getType();
    Object pk = id;
    if (type == Integer.class) {
        pk = Integer.parseInt(id);
    }
    return manager.find(TClass, pk);
}

对于更通用的方法(您不需要知道字段的名称),您可以选择检查所有字段上的 @Id 注释。有注解的就是你要解析的类型。例如

public T findById(String id) throws Exception {
    Field[] declaredFields = TClass.getDeclaredFields();
    Field idField = null;
    for (Field field: declaredFields) {
        if (field.isAnnotationPresent(Id.class)) {
            idField = field;
            break;
        }
    }
    if (idField == null) {
        throw new IllegalStateException("No field annotated with @Id");
    }
    Class<?> type = idField.getType();
    Object pk = id;
    if (type == Integer.class) {
        pk = Integer.parseInt(id);
    }
    return manager.find(TClass, pk);
}