Java枚举替代映射

时间:2016-10-07 13:45:02

标签: java orm enums mapping constants

尝试创建自己的闪亮ORM系统(不是那些重要信息),我目前正在努力克服java继承限制。这是概念:

public class UserDescriptor implements TableDescriptor {
    public static final UserDescriptor INSTANCE = new UserDescriptor();

    private UserDescriptor() {
    }

    public String getTableName() {
        return "user";
    }

    // ======= Columns definition
    public static final AbstractColumn<Integer> ID =
        new IntegerColumn("id", AbstractColumn.Attribute.NOT_NULL);

    public static final AbstractColumn<String> ALIAS =
        new StringColumn("alias");

    // ... and some more...
}

希望它足够清楚。然后将它们与静态导入一起使用,如:

map = JDBCHelper.selectFirst(UserDescriptor.INSTANCE, Arrays.asList(ID, ALIAS));

其中列表(2. param)是我需要从UserDescriptor定义的表中获取的内容。 map变量包含自定义地图,其内部具有类似于<AbstractColumn<T>, T>和方法

的签名
public T getValue(AbstractColumn<T> col);

所以我得到的值是类型安全的

    Integer id = map.getValue(ID);
    String alias = map.getValue(ALIAS);

这个概念目前正在运作,但是:

TableDescriptor概念有点冗长。我有很多表,需要多次写入两次类型和每个列定义的长开头

public static final AbstractColumn<Integer>

这一行是众所周知的java限制的结果 - 不可能扩展枚举类。否则TableDescriptor将是抽象类,其中字段AbstractColumn<T>由显式构造函数定义,并且每个后继将枚举实例中定义的列。 这将带来以下优势:

  1. 使整个事物(条件,返回列定义,.....)的可能性更加类型安全,例如。只有特定类型的枚举可以列在List参数中,用于从单个表中选择,
  2. 更好的可读性和新开发人员的基础,
  3. getAllColumns功能可以在没有反射的情况下完成。
  4. 遗憾的是,这是不可能的,所以你现在是我最后的希望。我知道enum继承的东西很多次,但我已经有了解决方案,也许在这种特殊情况下可以用其他方式改进它。

    什么可能是某种提示 - 这些描述符现在必须是项目的API部分才能选择。我正在努力解决这个问题。并且在API I中,只允许列出列的概述:

    public enum UserTableColumns {
        ID,
        ALIAS
    }
    

    并以某种方式将其映射到UserDescriptor - 然后我能够在大多数情况下仅使用此枚举,但我还没有弄清楚它应该如何工作..

    selectFisrt方法的当前签名如下:

    CustomResultMap selectFirst(TableDescriptor td, List<AbstractColumn<?>> cols);
    

    并且可能的一个修改是将List<AbstractColumn<?>>更改为某个枚举值列表,这些值将映射到TableDescriptor,以便我可以检查这些值是否来自单个表。

    编辑:澄清

1 个答案:

答案 0 :(得分:0)

我会尝试总结一下我从您的问题和评论中理解的内容:

您的API应包含类似UserTableColumn的枚举以及当前类似T get(AbstractColumn<T>)的方法,但应根据列的泛型类型返回正确的类型。由于AbstractColumn基本上是一个实现细节,因此您希望将其替换为枚举,例如得到这样的东西(不会编译):T get(UserTableColumn<T>)

(如果我在某个地方犯了错误,请纠正我。)

问题在于泛型是编译时工具,即编译器需要知道正在使用的类型。但是,枚举值不能具有泛型类型,并且任何参数(例如ID(Integer.class))在编译时都不可用,因为它基本上是实例(即运行时)值。

因此,您需要AbstractColumn<T>之类的东西,尽管这可能是另一个只包含泛型类型的类(并实现了一些接口)。这可能需要一些手动定义或使用预处理器(看看Hibernate如何为其标准api做这件事)。