NOTE: Please ignore my use of MultivaluedMap instead of multiple vargs String...args.
Is there a standard way in java of doing this?
What I have is a resource, that is returned from a remote server. But before each query, the remote connection must be open, and after the returns are returned - it must be closed.
So a natural way of doing this is something like:
Connection c = config.configureConnection();
c.open(); //open
List<Car> cars;
try{
cars = c.getCars();
}finally{
c.close(); //close
}
Now I want to implement something that operates on the level of the resources themselves, without worrying about connection, for example:
List<Car> cars = new CarResource().all(); //opens and closes connection
The way I am currently doing it is by having one abstract class, AbstractQueriable call abstract methods query(String ...args) and query(int id), which any class extending it must implement.
The AbstractQuerieable implements the Queriable interface, which makes it expose the three public methods filter(String ...args), all() and get(int id) - which are the public facing methods.
Here is the Queriable interface:
public interface Queriable <T>{
public T get(String id);
/** Simply returns all resources */
public Collection<T> all();
public Collection<T> filter(MultivaluedMap<String, String> args);
}
here is the AbstractQueriable class that implements it:
public abstract class AbstractQueriable<T> implements Queriable<T> {
#Override
public final T get(String id) {
setup();
try {
return query(id);
} finally {
cleanup();
}
}
#Override
public final Collection<T> filter(MultivaluedMap<String, String> args) {
setup();
try {
return query(args);
} finally {
cleanup();
}
}
/**
* Returns all resources.
*
* This is a convenience method that is equivalent to passing an empty
* arguments list to the filter function.
*
* #return The collection of all resources if possible
*/
#Override
public final Collection<T> all() {
return filter(null);
}
/**
* Queries for a resource by id.
*
* #param id
* id of the resource to return
* #return
*/
protected abstract T query(String id);
/**
* Queries for a resource by given arguments.
*
* #param args
* Map of arguments, where each key is the argument name, and the
* corresponing values are the values
* #return The collection of resources found
*/
protected abstract Collection<T> query(MultivaluedMap<String, String> args);
private void cleanup() {
Repository.close();
}
private void setup() {
Repository.open();
}
and finally my resource, which I want to use in the code, must extend the AbstractQueriable class, for example (please note that the details of these methods are not important):
public class CarRepositoryResource extends AbstractQueriable<Car> {
#Override
protected Car query(String id) {
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("CarID", id);
// Delegate the query to the parametarized version
Collection<cars> cars = query(params);
if (cars == null || cars.size() == 0) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
if (cars.size() > 1) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return cars.iterator().next();
}
#Override
protected Collection<Car> query(MultivaluedMap<String, String> params) {
Collection<Car> cars = new ArrayList<Car>();
Response response = Repository.getConnection().doQuery("Car");
while (response.next()) {
Returned returned = response.getResult();
if (returned != null) {
cars.add(returned);
}
}
return cars;
}
}
which finally, I can use in my code:
Collection<Car> cars = new CarRepositoryResource().all();
//... display cars to the client etc...
There are a few things I don't like about this kind of setup:
I must instantiate a new instance of my "CarRepositoryResource" every time I do a query.
The method names "query", while internal and private, are still confusing and clunky.
I am not sure if there is a better pattern or framework out there.
The connection that I am using does not support/implement the JDBC api and is not sql-based.
You could use a variation of the (in)famous Open session in view pattern.
Basically it comes down to this:
Define a "context" in which connections are available
(usually the request in web applications)
Handle (possibly lazy) initialization and release of a connection when entering/exiting the context
Code your methods taking for granted they will only be used inside such a context
It is not difficult to implement (storing the connection in a static ThreadLocal to make it thread safe) and will definitely spare a few open/close calls (performance-wise that could be a big gain, depending on how heavy your connection is).
The context class could look something like (consider this pseudo-code);
public class MyContext{
private static final
ThreadLocal<Connection> connection = new ThreadLocal<Connection>();
public static void enter() {
connection.set(initializeConnection());
// this is eager initialization
// if you think it will often the case that no connection is actually
// required inside a context, you can defer the actual initialization
// until the first call to get()
}
public static void exit() {
try { connection.close(); }
catch(Throwable t) { /* panic! */ }
finally { connection.set(null); }
}
public static Connection get() {
Connection c = connection.get();
if (c == null) throw new IllegalStateException("blah blah");
return c;
}
}
Then you would use connections like this:
MyContext.enter();
try {
// connections are available here:
// anything that calls MyContext.get()
// gets (the same) valid connection instance
} finally {
MyContext.exit();
}
This block can be put wherever you want (in webapps it usually wraps the processing of each request) - from the main method if you are coding a simple case when you want a single connection available for the whole lifespan of your application, to the finest methods in your API.
You might want to take a look at fluent interfaces (with an interesting example here) and its "Builder" pattern.
You would query like this:
cars().in(DB).where(id().isEqualTo(1234));
This way you can hide the connection/disconnection code in the outermost cars() method, for example.
Related
I have a library which parse URLs and extract some data. There is one class per URL. To know which class should handle the URL provided by the user, I have the code below.
public class HostExtractorFactory {
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
switch (host) {
case HostExtractorABC.HOST_NAME:
return HostExtractorAbc.getInstance();
case HostExtractorDEF.HOST_NAME:
return HostExtractorDef.getInstance();
case HostExtractorGHI.HOST_NAME:
return HostExtractorGhi.getInstance();
default:
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
}
The problem is users are requesting more URL to be parsed, which means my switch statement is growing. Every time someone comes up with a parser, I have to modify my code to include it.
To end this, I've decided to create a map and expose it to them, so that when their class is written, they can register themselves to the factory, by providing the host name, and the extractor to the factory. Below is the factory with this idea implemented.
public class HostExtractorFactory {
private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
if(EXTRACTOR_MAPPING.containsKey(host)) {
return EXTRACTOR_MAPPING.get(host);
} else {
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
public static void register(String hostname, HostExtractor extractor) {
if(StringUtils.isBlank(hostname) == false && extractor != null) {
EXTRACTOR_MAPPING.put(hostname, extractor);
}
}
}
And the user would use it that way:
public class HostExtractorABC extends HostExtractor {
public final static String HOST_NAME = "www.abc.com";
private static class HostPageExtractorLoader {
private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}
private HostExtractorABC() {
if (HostPageExtractorLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
HostExtractorFactory.register(HOST_NAME, this);
}
public static HostExtractorABC getInstance() {
return HostPageExtractorLoader.INSTANCE;
}
...
}
I was patting my own back when I realized this will never work: the user classes are not loaded when I receive the URL, only the factory, which means their constructor never runs, and the map is always empty. So I am back to the drawing board, but would like some ideas around getting this to work or another approach to get rid of this pesky switch statement.
S
Another option is to use the Service Loader approach.
Having your implementers add something like the following in ./resources/META-INF/services/your.package.HostExtractor:
their.package1.HostExtractorABC
their.package2.HostExtractorDEF
their.package3.HostExtractorGHI
...
Then in your code, you can have something like:
HostExtractorFactory() {
final ServiceLoader<HostExtractor> loader
= ServiceLoader.load(your.package.HostExtractor.class);
for (final HostExtractor registeredExtractor : loader) {
// TODO - Perform pre-processing which is required.
// Add to Map? Extract some information and store? Etc.
}
}
I would advice for you to learn about dependency injection (I love spring implementation). You will then be able to write an interface like
public interface HostExtractorHandler {
public String getName();
public HostExtractor getInstance();
}
Than your code can "ask" for all classes that implements this interface, you then would be able to build your map in the initialization phase of your class.
I would use the Reflections library to locate the parsers. They all appear to derive from the HostExtractor class, so use the library to locate all subtypes:
Reflections reflections = new Reflections("base.package");
Set<Class<? extends HostExtractor>> extractorTypes =
reflections.getSubTypesOf(HostExtractor.class);
Use the results to create the instances in your factory:
for (Class<? extends HostExtractor> c : extractorTypes) {
HostExtractor he = c.newInstance();
EXTRACTOR_MAPPING.put(he.getHostName(), he);
}
I made up the getHostName method, but it should be trivial to add to the HostExtractor base class.
I'm new to RxJava, and I am wondering how I can create a configurable Observable? Let's imagine I could write a DB-to-DB transfer like this:
srcDb.getObservable(Bean.class)
.sql(selectSql)
.params(selectParams)
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
I can already do that with the Subscriber, but how can I get some small configuration in the same fashion to the Observable itself?
There's 2 ways you can do that:
Option #1: have your own objects do the configuration, and then have an execute(), query() or toObservable() that switches domains:
srcDb
.find(Bean.class)
.sql(selectSql)
.params(selectParams)
.execute()
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
Option #2: use .compose() to re-use common operations:
srcDb
.getObservable(Bean.class)
.compose(addSQLParameters())
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
<T> Transformer<T,T> addSQLParameters() {
return obs -> obs.sql(selectSql).params(selectParams);
}
I would suggest you use option #1, as it allows much better management of your part of the code.
Maybe I found an acceptable way around this. It seems that what I need to do here is a double-binding outside of the Observable instantiation itself. E.g. I need a DbObservable and DbOnSubscribe pair which is counting on each other, something like this:
DbObservable class:
public class DbObservable<T> extends Observable<T> {
//Some parameter
private String sql;
protected DbObservable(DbOnSubscribe<T> onSub) {
super(onSub);
}
//Getter for DbOnSubscribe
public String getSql() {
return sql;
}
//Chain parameter modifier
public DbObservable<T> sql(String sql) {
this.sql = sql;
return this;
}
}
DbOnSubscribe class:
public class DbOnSubscribe<T> implements Observable.OnSubscribe<T> {
private DbObservable<T> dbObservable;
#Override
public void call(Subscriber<? super T> subscriber) {
String sql = dbObservable.getSql(); //Access SQL param
subscriber.onNext( (T) sql ); //Use subscriber
subscriber.onCompleted();
}
//Set back-reference
public void setDbObservable(DbObservable<T> dbObservable) {
this.dbObservable = dbObservable;
}
}
And finally our assumed DbConnector class:
public class DbConnector {
public DbObservable<String> getObservable() {
DbOnSubscribe<String> onSub = new DbOnSubscribe<String>();
DbObservable<String> obs = new DbObservable<>(onSub);
onSub.setDbObservable(obs);
return obs;
}
}
So when I try it out ...
public class DbObservableTest {
public static void main(String[] args) {
DbConnector srcDb = new DbConnector();
srcDb.getObservable()
.sql("some SQL")
.subscribe(System.out::println);
}
}
... it really works! It prints out the "some SQL".
Conclusion
If you want to be super-clean and don't mind one or 2 extra lines of code, go for a builder as proposed by Joel and Tassos Bassoukos.
If you're not afraid of a little bit more complicated code (which should be always encapsulated somewhere) and you really want those parameters to be inside your own Observable, you can try the double-binding way
Any more options?
While creating my app. architecture I faced the need for one structure, that will be described below.
I'm pretty sure, that there is a well known design pattern with the same functionality, because I think that problem, for which I develop it is really common.
I write my own implementation of this, but I always try to use "build in language" implementations of patterns, so - please help me to name this construction.
The idea is close to reader-writer pattern. We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
So, the implemented class should have two methods:
void putObject(Key key, Object object);
Object getObject(Key key); // remove <Key,Object> from container.
The next is most interesting.
This container should work in multi-threading environment as follows:
If there is no object associated with key, while calling get(Key
key) method the caller thread should WAIT for the object in this
container.
When another thread will call putObject(Key key, Object object)
method it should check if there is some thread that wait exactly for
this object, and if it is - then signal and wake up the thread that
waits.
I think that it is common structure, does it have "official" name?
My Java implementation of this pattern:
private static interface BlackBox {
public void addObject(IdObject object);
public IdObject getObject(ObjectId id);
}
private static class BlackBoxImpl implements BlackBox {
private final Lock conditionLock = new ReentrantLock();
private final Map<ObjectId, IdObject> savedObjects;
private final Map<ObjectId, Condition> waitingConditions;
public BlackBoxImpl() {
this.savedObjects = new ConcurrentHashMap<ObjectId, IdObject>(20);
this.waitingConditions = new ConcurrentHashMap<ObjectId, Condition>(20);
}
#Override
public void addObject(IdObject object) {
savedObjects.put(object.getId(), object);
if (waitingConditions.containsKey(object.getId())) {
Condition waitCondition = waitingConditions.get(object.getId());
conditionLock.lock();
waitCondition.signal();
conditionLock.unlock();
}
}
#Override
public IdObject getObject(ObjectId id) {
if (savedObjects.containsKey(id)) {
return savedObjects.get(id);
} else {
conditionLock.lock();
Condition waitCondition = conditionLock.newCondition();
waitingConditions.put(id, waitCondition);
waitCondition.awaitUninterruptibly();
conditionLock.unlock();
return savedObjects.get(id);
}
}
}
private static interface IdObject {
public ObjectId getId();
}
private static class IdObjectImpl implements IdObject {
protected final ObjectId id;
public IdObjectImpl(ObjectId id) {
this.id = id;
}
#Override
public ObjectId getId() {
return id;
}
}
private static interface ObjectId {
}
private static class ObjectIdImpl implements ObjectId {
}
I would probably use something like a
ConcurrentMap<K,BlockingQue<V>>.
Use the concurrent methods of the Map to add the pair. Take from your queue for the value. Use an ArrayBlockingQue(1).
Something like this perhaps:
static class MultiQueue<K, V> {
// The base structure.
final ConcurrentMap<K, BlockingQueue<V>> queues = new ConcurrentHashMap<>();
/**
* Put an item in the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be posted to the queue.
*/
public void put(K k, V v) throws InterruptedException {
// Make it if not present.
ensurePresence(k).put(v);
}
/**
* Get an item from the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be taken from the queue.
*/
public void get(K k) throws InterruptedException {
// Make it if not present - and wait for it.
ensurePresence(k).take();
}
private BlockingQueue<V> ensurePresence(K k) {
// Make it if not present.
return queues.computeIfAbsent(k, v -> new ArrayBlockingQueue(1));
}
}
Looking at your design, to me what you are describing
We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
This container should work in multi-threading environment
is close to concurrent Object pool. It uses a set of initialized objects kept ready to use. A client of the pool will request an object from the pool and perform operations on the returned object.
The only real difference I see is that you are getting the objects based on your own criteria.
I am playing with functional programming and in particular with Functional Java. I have implemented with success my version of the IO Monad and I am writing IO actions for my core. It is basically serializing objects to Xml files (the object type extends the custom XmlWritable interface).
Unfortunately, in order to do that, an instance of OutputStream AND one instance of XmlSerializer needs to be created. The scope of the OutputStream is wider than XmlSerializer's, which means that the only way I can see to be able to correctly handle both lifecycles within my IO monad is to carry both of them with me in a tuple, closing OutputStream after having written using XmlSerializer.
This leads to heavy and ugly code (Java 6 is definitely not the best for this):
public abstract class IO<R> {
[...]
}
public class IOActions {
public final F<String, IO<OutputStream>> openFileFn() {
return new F<String, IO<OutputStream>>() {
#Override
public IO<OutputStream> f(String fileName) {
[...]
}
};
}
/* This will be partially applied, encoding will be fixed */
public static final F<OutputStream, IO<P2<OutputStream, XmlSerializer>>> initSerializer() {
return new F<OutputStream, IO<P2<OutputStream, XmlSerializer>>>() {
#Override
public IO<P2<OutputStream, XmlSerializer>> f(OutputStream os) {
XmlSerializer = new ...
[...]
}
};
}
/* This will be partially applied as well */
public static final F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>> writeObjectFn() {
return new F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>>() {
#Override
public IO<P2<OutputStream, XmlSerializer>> f(XmlWritable object, P2<OutputStream, XmlSerializer> p) {
[...]
}
};
}
Is there a more idiomatic why to handle my use case in functional programming?
Lurking, I discovered the State Monad...but I am kind of scared to see what it is going to happen if I apply a State Monad on top of a IO Monad in Functional Java.
I actually took great inspiration from Functional-Java's DB combinators to solve similar problems. I made my very own "XML combinators" (and more) from this pattern, so its worth learning.
You might find this discussion on google groups useful.
edit - replying to the comment:
follow the code:
notice how you start a new connection using the StateDb, see that you have a few options to start a connection, one that eventually commits, and one that eventually rollback. these are just two examples of things you can "carry" with the computation. Essentially, every computation that you bind (a plain modaic bind), could potentially carry information.
here is an example i gave in the discussion above:
DB<PreparedStatement> prepareStatement(final String sql) {
return new DB<PreparedStatement>() {
public PreparedStatement run(Connection c) throws SQLException {
return c.prepareStatement(sql);
}}}
// for a query that a reader might perform, i might have a function like this:
F<PreparedStatement, DB<ResultSet>> runStatement() {
public DB<ResultSet> f(final PreparedStatement s) {
return new DB<ResultSet>() {
public ResultSet run (Connection c) throws SQLException {
return s.executeQuery();
}}}
So in this example, you can pass extra information, namely the sql query as a parameter to the function that gets bound. you could just as well had more parameters to runStatement.
to put it all together, you get something like:
ResultSet rs = DbState.reader("conn-url").run(prepareStatement("select * from table").bind(runStatement());
Hope this helps!
Here is what I have come up with. Feedback is very appreciated.
I followed the answer above, taking inspiration from the linked discussion:
public class IOXml<T extends XmlWritable> implements DataWriter<T>{
private final XmlSerializer mXmlSerializer;
private final Option<String> mXmlEncoding;
private final IO<OutputStream> ioCreateStream;
private final F<OutputStream, IO<Unit>> ioCloseStream;
#Inject
IOXml(IO<OutputStream> createStream, F<OutputStream, IO<Unit>> closeStream, XmlSerializer xmlSerializer, Option<String> xmlEncoding) {
mXmlSerializer = xmlSerializer;
mXmlEncoding = xmlEncoding;
ioCreateStream = createStream;
ioCloseStream = closeStream;
}
/**
* Write a T object which is XmlWritable.
* #param osAndSer The tuple containing OutputStream and XmlSerializer.
* #param object The object to write.
* #return IO monad object.
*/
protected IO<Unit> writeObject(final T object) {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
object.writeXml(mXmlSerializer);
return Unit.unit();
}
};
}
protected final F<Unit, IO<Unit>> writeObjectFn(final T object) {
return new F<Unit, IO<Unit>>() {
#Override
public IO<Unit> f(Unit a) {
return writeObject(object);
}
};
}
/**
* Initialize the XmlSerializer before using it.
* #param os An OutputStream.
* #param encoding The encoding of the xml file.
* #return An IO action returning nothing.
*/
protected IO<Unit> initXml(final OutputStream os) {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
mXmlSerializer.setOutput(os, mXmlEncoding.toNull());
mXmlSerializer.startDocument(mXmlEncoding.toNull(), true);
return Unit.unit();
}
};
}
/**
* Close the XmlSerializer after.
* #return An IO action returning nothing.
*/
protected IO<Unit> closeXml() {
return new IO<Unit>() {
#Override
public Unit performIO() throws IOException {
mXmlSerializer.endDocument();
return Unit.unit();
}
};
}
protected final F<Unit, IO<Unit>> closeXmlFn() {
return new F<Unit, IO<Unit>>() {
#Override
public IO<Unit> f(Unit a) {
return closeXml();
}
};
}
#Override
public void close() throws IOException {
closeXml().performIO();
}
#Override
public void write(T object) {
throw new UnsupportedOperationException("Are you sure? IOXml is a functional class. Use the function returned by liftIO instead.");
}
/**
* Curried function to write XML objects, given the object itself and an OutputStream.
* #return The curried function.
*/
protected F<OutputStream, F<T, IO<Unit>>> writeFn() {
// returning the outer
return new F<OutputStream, F<T, IO<Unit>>>() {
#Override
public F<T, IO<Unit>> f(final OutputStream os) {
// Returning the inner
return new F<T, IO<Unit>>() {
#Override
public IO<Unit> f(T object) {
return initXml(os).bind(writeObjectFn(object)).bind(closeXmlFn());
}
};
}
};
}
#Override
public IO<Unit> writeIO(final T object) {
return IOImpl.bracket(ioCreateStream, // init
ioCloseStream, // close
Function.partialApply2(writeFn(), object)); // body
}
}
I've got a class that implements Iterator with a ResultSet as a data member. Essentially the class looks like this:
public class A implements Iterator{
private ResultSet entities;
...
public Object next(){
entities.next();
return new Entity(entities.getString...etc....)
}
public boolean hasNext(){
//what to do?
}
...
}
How can I check if the ResultSet has another row so I can create a valid hasNext method since ResultSet has no hasNext defined itself? I was thinking doing SELECT COUNT(*) FROM... query to get the count and managing that number to see if there's another row but I'd like to avoid this.
This is a bad idea. This approach requires that the connection is open the whole time until the last row is read, and outside the DAO layer you never know when it will happen, and you also seem to leave the resultset open and risk resource leaks and application crashes in the case the connection times out. You don't want to have that.
The normal JDBC practice is that you acquire Connection, Statement and ResultSet in the shortest possible scope. The normal practice is also that you map multiple rows into a List or maybe a Map and guess what, they do have an Iterator.
public List<Data> list() throws SQLException {
List<Data> list = new ArrayList<Data>();
try (
Connection connection = database.getConnection();
Statement statement = connection.createStatement("SELECT id, name, value FROM data");
ResultSet resultSet = statement.executeQuery();
) {
while (resultSet.next()) {
list.add(map(resultSet));
}
}
return list;
}
private Data map(ResultSet resultSet) throws SQLException {
Data data = new Data();
data.setId(resultSet.getLong("id"));
data.setName(resultSet.getString("name"));
data.setValue(resultSet.getInteger("value"));
return data;
}
And use it as below:
List<Data> list = dataDAO.list();
int count = list.size(); // Easy as that.
Iterator<Data> iterator = list.iterator(); // There is your Iterator.
Do not pass expensive DB resources outside the DAO layer like you initially wanted to do. For more basic examples of normal JDBC practices and the DAO pattern you may find this article useful.
You can get out of this pickle by performing a look-ahead in the hasNext() and remembering that you did a lookup to prevent consuming too many records, something like:
public class A implements Iterator{
private ResultSet entities;
private boolean didNext = false;
private boolean hasNext = false;
...
public Object next(){
if (!didNext) {
entities.next();
}
didNext = false;
return new Entity(entities.getString...etc....)
}
public boolean hasNext(){
if (!didNext) {
hasNext = entities.next();
didNext = true;
}
return hasNext;
}
...
}
ResultSet has an 'isLast()' method that might suit your needs. The JavaDoc says it is quite expensive though since it has to read ahead. There is a good chance it is caching the look-ahead value like the others suggest trying.
You can use ResultSetIterator, just put your ResultSet in the constructor.
ResultSet rs = ...
ResultSetIterator = new ResultSetIterator(rs);
One option is the ResultSetIterator from the Apache DBUtils project.
BalusC rightly points out the the various concerns in doing this. You need to be very careful to properly handle the connection/resultset lifecycle. Fortunately, the DBUtils project also has solutions for safely working with resultsets.
If BalusC's solution is impractical for you (e.g. you are processing large datasets that can't all fit in memory) you might want to give it a shot.
public class A implements Iterator<Entity>
{
private final ResultSet entities;
// Not required if ResultSet.isLast() is supported
private boolean hasNextChecked, hasNext;
. . .
public boolean hasNext()
{
if (hasNextChecked)
return hasNext;
hasNext = entities.next();
hasNextChecked = true;
return hasNext;
// You may also use !ResultSet.isLast()
// but support for this method is optional
}
public Entity next()
{
if (!hasNext())
throw new NoSuchElementException();
Entity entity = new Entity(entities.getString...etc....)
// Not required if ResultSet.isLast() is supported
hasNextChecked = false;
return entity;
}
}
Its not a really bad idea in the cases where you need it, it's just that you often do not need it.
If you do need to do something like, say, stream your entire database.... you could pre-fetch the next row - if the fetch fails your hasNext is false.
Here is what I used:
/**
* #author Ian Pojman <pojman#gmail.com>
*/
public abstract class LookaheadIterator<T> implements Iterator<T> {
/** The predetermined "next" object retrieved from the wrapped iterator, can be null. */
protected T next;
/**
* Implement the hasNext policy of this iterator.
* Returns true of the getNext() policy returns a new item.
*/
public boolean hasNext()
{
if (next != null)
{
return true;
}
// we havent done it already, so go find the next thing...
if (!doesHaveNext())
{
return false;
}
return getNext();
}
/** by default we can return true, since our logic does not rely on hasNext() - it prefetches the next */
protected boolean doesHaveNext() {
return true;
}
/**
* Fetch the next item
* #return false if the next item is null.
*/
protected boolean getNext()
{
next = loadNext();
return next!=null;
}
/**
* Subclasses implement the 'get next item' functionality by implementing this method. Implementations return null when they have no more.
* #return Null if there is no next.
*/
protected abstract T loadNext();
/**
* Return the next item from the wrapped iterator.
*/
public T next()
{
if (!hasNext())
{
throw new NoSuchElementException();
}
T result = next;
next = null;
return result;
}
/**
* Not implemented.
* #throws UnsupportedOperationException
*/
public void remove()
{
throw new UnsupportedOperationException();
}
}
then:
this.lookaheadIterator = new LookaheadIterator<T>() {
#Override
protected T loadNext() {
try {
if (!resultSet.next()) {
return null;
}
// process your result set - I use a Spring JDBC RowMapper
return rowMapper.mapRow(resultSet, resultSet.getRow());
} catch (SQLException e) {
throw new IllegalStateException("Error reading from database", e);
}
}
};
}
I agree with BalusC. Allowing an Iterator to escape from your DAO method is going to make it difficult to close any Connection resources. You will be forced to know about the connection lifecycle outside of your DAO, which leads to cumbersome code and potential connection leaks.
However, one choice that I've used is to pass a Function or Procedure type into the DAO method. Basically, pass in some sort of callback interface that will take each row in your result set.
For example, maybe something like this:
public class MyDao {
public void iterateResults(Procedure<ResultSet> proc, Object... params)
throws Exception {
Connection c = getConnection();
try {
Statement s = c.createStatement(query);
ResultSet rs = s.executeQuery();
while (rs.next()) {
proc.execute(rs);
}
} finally {
// close other resources too
c.close();
}
}
}
public interface Procedure<T> {
void execute(T t) throws Exception;
}
public class ResultSetOutputStreamProcedure implements Procedure<ResultSet> {
private final OutputStream outputStream;
public ResultSetOutputStreamProcedure(OutputStream outputStream) {
this.outputStream = outputStream;
}
#Override
public void execute(ResultSet rs) throws SQLException {
MyBean bean = getMyBeanFromResultSet(rs);
writeMyBeanToOutputStream(bean);
}
}
In this way, you keep your database connection resources inside your DAO, which is proper. But, you are not necessarily required to fill a Collection if memory is a concern.
Hope this helps.
You could try the following:
public class A implements Iterator {
private ResultSet entities;
private Entity nextEntity;
...
public Object next() {
Entity tempEntity;
if ( !nextEntity ) {
entities.next();
tempEntity = new Entity( entities.getString...etc....)
} else {
tempEntity = nextEntity;
}
entities.next();
nextEntity = new Entity( entities.getString...ext....)
return tempEntity;
}
public boolean hasNext() {
return nextEntity ? true : false;
}
}
This code caches the next entity, and hasNext() returns true, if the cached entity is valid, otherwise it returns false.
There are a couple of things you could do depending on what you want your class A. If the major use case is to go through every single result then perhaps its best to preload all the Entity objects and throw away the ResultSet.
If however you don't want to do that you could use the next() and previous() method of ResultSet
public boolean hasNext(){
boolean next = entities.next();
if(next) {
//reset the cursor back to its previous position
entities.previous();
}
}
You do have to be careful to make sure that you arent currently reading from the ResultSet, but, if your Entity class is a proper POJO (or at least properly disconnected from ResultSet then this should be a fine approach.
Here's my iterator that wraps a ResultSet. The rows are returned in the form a Map. I hope you'll find it helpful. The strategy is that I always bring one element in advance.
public class ResultSetIterator implements Iterator<Map<String,Object>> {
private ResultSet result;
private ResultSetMetaData meta;
private boolean hasNext;
public ResultSetIterator( ResultSet result ) throws SQLException {
this.result = result;
meta = result.getMetaData();
hasNext = result.next();
}
#Override
public boolean hasNext() {
return hasNext;
}
#Override
public Map<String, Object> next() {
if (! hasNext) {
throw new NoSuchElementException();
}
try {
Map<String,Object> next = new LinkedHashMap<>();
for (int i = 1; i <= meta.getColumnCount(); i++) {
String column = meta.getColumnName(i);
Object value = result.getObject(i);
next.put(column,value);
}
hasNext = result.next();
return next;
}
catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
}
entities.next returns false if there are no more rows, so you could just get that return value and set a member variable to keep track of the status for hasNext().
But to make that work you would also have to have some sort of init method that reads the first entity and caches it in the class. Then when calling next you would need to return the previously cached value and cache the next value, etc...
Iterators are problematic for traversing ResultSets for reasons mentioned above but Iterator like behaviour with all the required semantics for handling errors and closing resources is available with reactive sequences (Observables) in RxJava. Observables are like iterators but include the notions of subscriptions and their cancellations and error handling.
The project rxjava-jdbc has implementations of Observables for jdbc operations including traversals of ResultSets with proper closure of resources, error handling and the ability to cancel the traversal as required (unsubscribe).
Do you expect most of the data in your result set to actually be used? If so, pre-cache it. It's quite trivial using eg Spring
List<Map<String,Object>> rows = jdbcTemplate.queryForList(sql);
return rows.iterator();
Adjust to suit your taste.
I think there's enough decry over why it's a really bad idea to use ResultSet in an Iterator (in short, ResultSet maintains an active connection to DB and not closing it ASAP can lead to problems).
But in a different situation, if you're getting ResultSet (rs) and are going to iterate over the elements, but you also wanted to do something before the iteration like this:
if (rs.hasNext()) { //This method doesn't exist
//do something ONCE, *IF* there are elements in the RS
}
while (rs.next()) {
//do something repeatedly for each element
}
You can achieve the same effect by writing it like this instead:
if (rs.next()) {
//do something ONCE, *IF* there are elements in the RS
do {
//do something repeatedly for each element
} while (rs.next());
}
It can be done like this:
public boolean hasNext() {
...
return !entities.isLast();
...
}
It sounds like you are stuck between either providing an inefficient implementation of hasNext or throwing an exception stating that you do not support the operation.
Unfortunately there are times when you implement an interface and you don't need all of the members. In that case I would suggest that you throw an exception in that member that you will not or cannot support and document that member on your type as an unsupported operation.