Универсальный метод, возвращающий список при создании экземпляра универсального типа, переданного в метод - PullRequest
0 голосов
/ 30 апреля 2018

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

Некоторые примеры включали использование интерфейса Supplier или предлагали создать универсальный класс, а затем создать его экземпляр.

То, чего я пытаюсь достичь, - это указать тип, который я хочу, чтобы метод возвращал при создании экземпляра того же типа в методе, добавить его в список и затем вернуть этот список.

Заранее спасибо. Буду признателен за любую помощь

public List<Doctor> queryDoctor() {
    Statement statement = null;
    ResultSet results;

    try {
        statement = connection.createStatement();
        results = statement.executeQuery("SELECT * FROM " + TABLE_DOCTOR);

        List<Doctor> doctors = new ArrayList<>();
        while (results.next()) {
            Doctor doctor = new Doctor();
            doctor.setId(results.getInt(1));
            doctor.setUserName(results.getString(2));
            doctor.setPassword(results.getString(3));
            doctor.setPassword_salt(results.getString(4));
            doctor.setRole(results.getInt(5));
            doctors.add(doctor);

        }
        return doctors;
    } catch (SQLException e) {
        System.out.println("Query failed: " + e.getMessage());
        return null;
    } finally {
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Похоже, что вы пытаетесь создать собственное простое решение ORM, в котором вы предоставляете метод со строкой и типом SQL, метод загружает результаты, а затем создает экземпляр типа, сопоставляя результирующий набор с полями объекта с помощью установщиков.

Если это так, вы изобретаете велосипед.

Полным решением было бы использование инструмента ORM, такого как Hibernate или Top Link, но он может быть запущен до того, как вы сможете ходить. Если вы предпочитаете детские шаги, рассмотрите возможность использования Spring Jdbc Template для обработки большого количества стандартного кода.

UPDATE

ОК, я спросил, ищите ли вы метод, который взял бы набор результатов и сопоставил его с произвольным классом, и вы сказали «да». Это должно сделать что-то вроде этого:

public <T> List<T> map(ResultSet rs, Class<T> clazz) throws Exception {
    //// Build a list of columns that are in the resultset
    List<String> columns = new LinkedList<>();
    ResultSetMetaData metaData = rs.getMetaData();
    for(int i=0; i < metaData.getColumnCount(); i++) {
        columns.add(metaData.getCatalogName(i));
    }

    //// Create a list to hold all the beans we are going to create from the resultset 
    List<T> rows = new LinkedList<>();

    //// Iterate over each row in the resultset, creating beans for each row and setting the values 
    while(rs.next()) {
        //// Create a new instance of the class passed in (must have a no-args constructor) 
        T row = clazz.newInstance();

        //// Now for the magic. This bit is very noddy and ORM packages will do this much better 
        for(String col : columns) {
            //// For each column that is in the resultset, find the setter in the bean class 
            String columnValue = rs.getString(col);
            String mutator = "set"+capitalizeFirstCharacter(col);
            Method m = clazz.getMethod(mutator, String.class);
            //// Invoke the setter, passing in the value from the resultset 
            m.invoke(row, columnValue);
        }

        rows.add(row);
    }

    return rows;
}

private static String capitalizeFirstCharacter(String s) {
    return s.substring(0, 1).toUpperCase() + s.substring(1);
}

Помните, что этот код не работает с исключениями, работает только с наборами результатов, заполненными строками, и только с бобами, в которых есть поля String для заполнения. Как только вы начинаете пытаться писать более сложный код, чтобы иметь дело с более сложными типами и отражениями ... вы заново изобретаете ORM. Постарайся не делать этого.

0 голосов
/ 30 апреля 2018

Вам нужно будет передать в Function<ResultSet, T>:

<T> List<T> queryDoctor(Function<ResultSet, T> fn)

и используйте это в цикле:

doctors.add(fn.apply(results));

Эта функция создаст соответствующий тип бетона:

List<Doctor> doctors = queryDoctor(results -> {
       Doctor doctor = new Doctor();
        doctor.setId(results.getInt(1));
        doctor.setUserName(results.getString(2));
        doctor.setPassword(results.getString(3));
        doctor.setPassword_salt(results.getString(4));
        doctor.setRole(results.getInt(5));
        return doctor;
});

или

List<Nurse> nurses = queryDoctor(results -> {
       Nurse nurse = new Nurse();
       // ...
       return nurse;
});
...