Перечисления Java с родовыми классами - PullRequest
4 голосов
/ 16 октября 2011

Я переключаю передачи из интерпретируемого мира и пытаюсь с большим успехом воспроизвести шаблон, который использовал в переданном, но в Java.

Короче говоря, я делаю пользовательский DAO (не использую Hibernate или что-то в этом роде ... в конечном итоге это будет универсально для обработки различных механизмов баз данных (SQL и NoSQL). Для взлома я просто использую MySQL / Prepared Statements.

Я хочу в основном определитьобъект DataMapper, который отвечает за сопоставление поля записи с полями в базе данных. Я пытаюсь инкапсулировать любую избыточную логику для деталей реализации преобразования типа в формат, ожидаемый базой данных. В 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();
    }
}

Очевидно, я пытался урезать пример до значимых частей. Код клиента для выполнения этого

    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());

       }

Проблема, с которой я сталкиваюсь, связана споследняя строка. Я пытаюсь использовать общий объект, связанный с entryId enum, чтобы использовать его специальную функцию setValue, которая обрабатывает получение Integer в правильном формате.Моя среда разработки выдает мне следующую ошибку: Метод setValue (PreparedStatement, int, capture # 13-of?) В типе AbstractDataMapper.Field не применим для аргументов (PreparedStatement, int, Integer).

Я уверен, что смогу попасть в серию сумасшедших типов… но на этом этапе, вероятно, будет проще раскрыть детали перевода.

Любые идеи о том, как заставить это работать или модификацию этого шаблона.так лучше?

Ответы [ 2 ]

3 голосов
/ 16 октября 2011

enum не может быть универсальным, поэтому есть проблема для вашего случая.

более простой способ кастования будет

public static enum Field {

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

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

Большой вопрос, какой смыслиспользования enum здесь?Было бы намного проще использовать некоторые статические открытые конечные поля.

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());
0 голосов
/ 16 октября 2011

Это происходит потому, что поле в перечислении является AbstractDataMapper.Field<?>, а не AbstractDataMapper.Field<Integer>.Когда вы вызываете setValue для него, он ожидает некоторый тип, который компилятор идентифицирует как «capture # 13-of?», А не Integer (или int, который автоматически помещается в Integer).

Если вы собираетесь поместить поля с различными, не связанными типами данных в перечисление Field, то на самом деле нет другого способа, кроме как объявить переменную-член field как AbstractDataMapper.Field<?> (со знаком вопроса),и вы не избежите разыграть его, когда вам нужно его использовать.Вы можете добавить аннотацию @SuppressWarnings для подавления предупреждения компилятора:

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

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