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 :frowning:

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

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

···

On 8 January 2011 00:05, Bob Jolliffe <bobjolliffe@gmail.com> wrote:

I have to confess i have a much better understanding of C++
generics than the Java variant, which is probably working against me
here :frowning:

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