How to implements a method of a generic interface?

user4789408 :

I have this interface:

public interface ParsableDTO<T> {
    public <T> T parse(ResultSet rs) throws SQLException;
}

Implemented in some kind of dto classes and this method in another class:

public <T extends ParsableDTO<T>> List<T> getParsableDTOs(String table, 
                                                          Class<T> dto_class) {
    List<T> rtn_lst = new ArrayList<T>();
    ResultSet rs = doQueryWithReturn(StringQueryComposer
            .createLikeSelectQuery(table, null, null, null, true));

    try {
        while(rs.next()) {
            rtn_lst.add(T.parse(rs)); //WRONG, CAN'T ACCESS TO parse(...) OF ParsableDTO<T>
        }
        rs.close();
    } catch (SQLException e) {
        System.err.println("Can't parse DTO from " 
                + table + " at " + dateformat.format(new Date()));
        System.err.println("\nError on " + e.getClass().getName() 
                + ": " + e.getMessage());
        e.printStackTrace();
    }

    return rtn_lst;
}

How can I access the method parse(ResultSet rs) of the interface that can parse a specific T? Is there a working, different and/or better method to do that?

NoDataFound :

You are trying to call a non static method on a generic, which is erased when compiled. Even if the method was static, there is no way the compiler would allow that (because T is ParseableDTO in that case, and never the concrete implementation).

Instead, assuming you are in Java 8, I would do:

@FunctionalInterface
public interface RowMapper<T> {
    T mapRow(ResultSet rs) throws SQLException;
}

And then:

public <T> List<T> getParsableDTOs(String table, RowMapper<T> mapper) {
    try (ResultSet rs = doQueryWithReturn(StringQueryComposer
            .createLikeSelectQuery(table, null, null, null, true))) {
        List<T> rtn_lst = new ArrayList<T>();
        while(rs.next()) {
            rtn_lst.add(mapper.mapRow(rs));
        }
        return rtn_lst;
    } catch (SQLException e) {
        // ...
    }

    return rtn_lst;
}

The interface RowMapper is derived from existing framework, such as JDBC Template.

The idea is to separate concerns: the DTO is not polluted by JDBC related method (eg: mapping or parsing, but I suggest you to avoid the parse name as you are not really parsing a SQL ResultSet here), and you may even leave the mapping in the DAO (lambda make it easier to implements).

Polluting the DTO with JDBC may be problematic because the client/caller will probably not have a valid ResultSet to pass to the parse. Worse: in newer JDK (9++), the ResultSet interface is in the java.sql module which may be unavailable (if you think about a web service, the client does not need JDBC at all).

On a side note, from Java 7 onward, you may use try-with-resource with the ResultSet to automatically close it in a safer way: in your implementation, you are only closing the ResultSet if there was no errors.

If you are stuck with Java 6, you should use the following idiom:

   ResultSet rs = null;
   try {
     rs = ...; // obtain rs
     // do whatever
   } finally {
     if (null != rs) {rs.close();}
   }

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=438715&siteId=1