← Back to team overview

dhis2-devs team mailing list archive

Fwd: A question on generics

 

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.  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



Follow ups