← Back to team overview

dhis2-devs team mailing list archive

Re: A question on generics

 

On 8 January 2011 00:05, Bob Jolliffe <bobjolliffe@xxxxxxxxx> wrote:
> Hi all
>
> I have a small problem which I can't seem to get right.  I am sure
> Lars, Jo, Saptarshi and all ye java experts will know.  Lars I guess
> you are pretty familiar with the amplecode jdbc stuff.
>
> I have an interface and a class for iterating over a result set from a
> query on the aggregatedatavalue table:
>
> the interface:
>
> package org.hisp.dhis.aggregation;
>
> public interface AggregatedDataValueStoreIterator {
>
>    // ----------------------------------------------------------------------
>    // AggregatedDataValueStoreIterator
>    // ----------------------------------------------------------------------
>
>    /**
>     * Gets the next AggregatedDataValue
>     *
>     * @return the aggregated value or null.
>     */
>    AggregatedDataValue next();
>
>    /**
>     * Close any underlying resources
>     *
>     */
>    void close();
> }
>
> and the class:
>
> public class JdbcAggregatedDataValueStoreIterator implements
> AggregatedDataValueStoreIterator {
>
>    private static final Log log =
> LogFactory.getLog(AggregatedDataValueStoreIterator.class);
>
>    static RowMapper<AggregatedDataValue> rowmapper = new
> AggregatedDataValueRowMapper();
>
>    private ResultSet resultSet;
>
>    public ResultSet getResultSet() {
>        return resultSet;
>    }
>
>    public void setResultSet(ResultSet resultSet) {
>        this.resultSet = resultSet;
>    }
>
>    private StatementHolder holder;
>
>    public StatementHolder getHolder()
>    {
>        return holder;
>    }
>
>    public void setHolder( StatementHolder holder )
>    {
>        this.holder = holder;
>    }
>
>    public JdbcAggregatedDataValueStoreIterator(ResultSet resultSet,
> StatementHolder holder) {
>        this.resultSet = resultSet;
>        this.holder = holder;
>    }
>
>    @Override
>    public AggregatedDataValue next() {
>        AggregatedDataValue row = null;
>        try {
>            if (resultSet.next()) {
>                row = rowmapper.mapRow(resultSet);
>            } else {
>                this.close();
>            }
>        } catch (SQLException ex) {
>            log.warn("Error reading aggregateddatavalue row: " + ex);
>        }
>        return row;
>    }
>
>    @Override
>    public void close() {
>        try {
>            if (!resultSet.isClosed()) {
>                resultSet.close();
>            }
>        } catch (SQLException ex) {
>            log.warn("Error closing resultset: " + ex);
>        }
>
>        holder.close();
>    }
> }
>
> This works very well, but now I also want to iterate over aggregate
> indicator values.  Now obviously I could just copy and paste the above
> with minor adjustments, but it seems to makes sense to do this more
> generically.  95% of the code in the class is pretty generic.  What I
> would like instead to have is an interface like:
>
> public interface StoreIterator<T> {
>
>   // ----------------------------------------------------------------------
>   // generic StoreIterator
>   // ----------------------------------------------------------------------
>
>   /**
>    * Gets the next object value
>    *
>    * @return the object value or null.
>    */
>   T next();
>
>   /**
>    * Close any underlying resources
>    *
>    */
>   void close();
> }
>
> That would be fine and dandy, but I can't implement the class
>
> public class JdbcStoreIterator<T> implements StoreIterator<T>
>
> by parameterizing the above JdbcAggregatedDataValueStoreIterator
> class.  The problem has to do with the rowmapper in the class.
>
> I can't say:
>
> static RowMapper<T> rowmapper = new AggregatedDataValueRowMapper();
>
> because T is generic so I don't know the type of the rowmapper in
> advance and the AggregateDataValueRowMapper (presumably like all the
> other row mappers) is declared like:
>
> public class AggregatedDataValueRowMapper
>    implements RowMapper<AggregatedDataValue>
>
> In desperation I tried adding an extra type parameter to the
> JdbcStoreIterator, like
>
> public class JdbcStoreIterator<T, R> implements StoreIterator<T>
>
> to pass in the rowmapper type, but it still defeats me - you can't
> "simply" instantiate a new object based on a Type and various tricks
> around Class<R> and getInstance() don't seem to work.
>
> Anybody have any good ideas of the best way to do this?  Maybe I can
> pass in a concrete RowMapper<T> into the JdbcStoreIterator<T>
> constructor?  Just thought of that now as a possibility and haven't
> tried it.

OK I just answered my own question.  That works.  Pleased as a pig in
sh**!. Sorry for the long email ...

>I have to confess i have a much better understanding of C++
> generics than the Java variant, which is probably working against me
> here :-(
>
> Failing which I will either return to copy and paste (which would have
> taken all of half an hour instead of 3 hours puzzling over this) or
> just do away with using the rowmapper at all and just program directly
> to the jdbc resultset.
>
> Cheers
> Bob
>



References