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