简体   繁体   English

带有通用类的Java枚举

[英]Java Enums with Generic Classes

I am switching gears from the interpreted world and I am trying to replicate a pattern I have used in the passed with great success but in Java. 我正在从解释的世界转换齿轮,我试图复制我在传递中使用的模式,但在Java中取得了巨大的成功。

The short of it is I am making a custom DAO (not using Hibernate or anything like that...ultimately it will be generic to handle different database engines (SQL and NoSQL). For breaking into I am just using a MySQL/ Prepared Statements. 缺点是我正在制作一个自定义DAO(不使用Hibernate或类似的东西......最终处理不同的数据库引擎(SQL和NoSQL)将是通用的。为了突破我只是使用MySQL / Prepared Statementments 。

I want to basically define a DataMapper object that is responsible for mapping the field of a record to the fields in a database. 我想基本上定义一个DataMapper对象,负责将记录的字段映射到数据库中的字段。 I am trying to encapsulate any redundant logic for implementation details of transforming a type to the format the database expects. 我试图封装任何冗余逻辑,以实现将类型转换为数据库期望格式的实现细节。 In the DataMapper I am trying to utilize an enum to list the fields: 在DataMapper中,我试图利用枚举列出字段:

public abstract class AbstractDataMapper<X> {

public static abstract class Field<Y> {
    protected String name;
    public Field(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    public abstract void setValue(PreparedStatement stmt, int parameterIndex, Y value) 
        throws SQLException;
    public abstract Y getValue(ResultSet rset)
        throws SQLException;
}

public static class IntegerField extends AbstractDataMapper.Field<Integer> {

    public IntegerField(String name) {
        super(name);
    }

    @Override
    public void setValue(PreparedStatement stmt, int parameterIndex,
            Integer value) throws SQLException {
        stmt.setInt(parameterIndex, value.intValue());
    }

    @Override
    public Integer getValue(ResultSet rset) throws SQLException {
        return new Integer(rset.getInt(this.name));
    }
}
}


public class UserDataMapper extends AbstractDataMapper<UserDataRecord>{
    public static enum Field {
    entryId(new AbstractDataMapper.IntegerField("entryid"));

    AbstractDataMapper.Field<?> field = null;

    Field(AbstractDataMapper.Field<?> field) {
        this.field = field;
    }

    public AbstractDataMapper.Field<?> getField() {
        return this.field;
    }

    public String getName() {
        return this.field.getName();
    }
}

Obviously I tried to truncate the example to the meaningful parts. 显然,我试图将示例截断为有意义的部分。 The client code for exercising this 用于执行此操作的客户端代码

    public int insert(UserDataRecord user) {
    ...
        final String query = 
            "INSERT INTO users SET "
            + UserDataMapper.Field.entryId.getName() + " = ? ";

        stmt = conn.prepareStatement(query);
        UserDataMapper.Field.entryId.getField()
            .setValue(stmt, 1, user.getEntryId());

       }

The issue I am encountering is with the last line. 我遇到的问题是最后一行。 I am trying to use the generic object associated with the entryId enum to use it's special setValue function which handles getting the Integer into the proper format. 我试图使用与entryId枚举关联的泛型对象来使用它的特殊setValue函数,该函数处理将Integer转换为正确的格式。 My IDE is giving me the following error: The method setValue(PreparedStatement, int, capture#13-of ?) in the type AbstractDataMapper.Field is not applicable for the arguments (PreparedStatement, int, Integer). 我的IDE给出了以下错误:AbstractDataMapper.Field类型的方法setValue(PreparedStatement,int,capture#13-of?)不适用于参数(PreparedStatement,int,Integer)。

I am sure I could get into a series of crazy typecasts...but at that point it would probably just be easier to expose the translation details. 我相信我可以进入一系列疯狂的类型转换......但在那时,它可能会更容易暴露翻译细节。

Any ideas on getting this to work or a modification to this pattern that is better? 有关实现此功能或修改此模式的任何想法更好吗?

enum can't be generic, so there's a problem for your case. enum不能是通用的,所以你的情况有问题。

a simpler way of casting would be 一种更简单的铸造方式

public static enum Field {

public <T> AbstractDataMapper.Field<T> getField() {
    return (AbstractDataMapper.Field<T>)this.field;
}

// usage
UserDataMapper.Field.entryId.<Integer>getField()

The bigger question is, what's the point of using enum here? 更大的问题是,在这里使用enum什么意义? It would be much simpler to use some static public final fields. 使用一些静态公共最终字段会简单得多。

public class UserDataMapper extends AbstractDataMapper<UserDataRecord>{

    public interface Fields {
        IntegerField entryId = new IntegerField("entryid"));

----

    final String query = 
        "INSERT INTO users SET "
        + UserDataMapper.Field.entryId.getName() + " = ? ";

    stmt = conn.prepareStatement(query);
    UserDataMapper.Field.entryId
        .setValue(stmt, 1, user.getEntryId());

This happens because the field in the enum is an AbstractDataMapper.Field<?> and not an AbstractDataMapper.Field<Integer> . 发生这种情况是因为枚举中的字段是AbstractDataMapper.Field<?>而不是AbstractDataMapper.Field<Integer> When you call setValue on it, it expects some type that the compiler identifies as "capture#13-of ?", and not an Integer (or int which is autoboxed to an Integer ). 当你在它上面调用setValue时,它需要一些编译器识别为“capture#13-of?”的类型,而不是一个Integer (或者是一个自动装箱到Integer int )。

If you are going to put fields with different, unrelated data types in the Field enum, then there's really no other way than to declare the field member variable as AbstractDataMapper.Field<?> (with the question mark), and you're not going to avoid to cast it when you need to use it. 如果你要在Field枚举中放置具有不同的,不相关的数据类型的Field ,那么除了将field成员变量声明为AbstractDataMapper.Field<?> (带有问号)之外别无其他方法,而你不是当你需要使用它时,要避免使用它。 You could add a @SuppressWarnings annotation to suppress the compiler warning: 您可以添加@SuppressWarnings注释来禁止编译器警告:

@SuppressWarnings("unchecked")
AbstractDataMapper.Field<Integer> field =
    (AbstractDataMapper.Field<Integer>)UserDataMapper.Field.entryId.getField();

field.setValue(stmt, 1, user.getEntryId());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM