Chris Farmer
Chris Farmer

Reputation: 25396

How to programmatically create a Java ResultSet from custom data with no database

I have some existing code that accepts a java.sql.ResultSet that contains info retrieved from an Oracle database. I would now like to reuse this code, but I'd like to pass it a ResultSet object that I create myself from some in-memory data that is not affiliated with any database. Is there an existing Java framework class that I can use for this? ResultSet has tons of methods, so implementing my own class for this seemed like overkill, even though I could ignore most of the methods for my specific case.

I was thinking of something along the lines of the old Microsoft ADO recordset object, where I could create the fields and then populate the row data for each field. This seemed like an easily googlable question, but I've been unable to find any good pointers.

Upvotes: 33

Views: 50174

Answers (8)

JRichardsz
JRichardsz

Reputation: 16505

If you need the ResultSet for unit test purposes, you could try this:

https://gist.githubusercontent.com/jrichardsz/661913b8d52b6e820a1b37b972ffdb49/raw/4fc10e4624795b9671d43c5ac9169aa2ae532266/MockResultSet.java

Just needs one dependency:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
</dependency>

It works like a charm:

ResultSet mockResultSet = MockResultSet.create(
    new String[] {"name", "lastname"},
    new String[][] {{"jane", "doe"}, {"kurt", "weller"}}
);

Upvotes: 0

Lukas Eder
Lukas Eder

Reputation: 220797

jOOQ has a MockResultSet for that and similar purpose, which can be used out of the box, or copied into your project.

DSLContext ctx = DSL.using(DEFAULT);
Field<Integer> col1 = DSL.field("COL1", SQLDataType.INTEGER);
Field<String> col2 = DSL.field("COL2", SQLDataType.VARCHAR(10));

Result<?> result = ctx.newResult(col1, col2);
result.add(ctx.newRecord(col1, col2).values(1, "a"));
result.add(ctx.newRecord(col1, col2).values(2, "b"));

try (ResultSet rs = new MockResultSet(result)) {
    while (rs.next())
        System.out.println(rs.getInt(1) + ": " + rs.getString(2));
}

Disclaimer: I work for the company behind jOOQ.

Upvotes: 4

Joel Shemtov
Joel Shemtov

Reputation: 3078

  • Create your own AbstractResultSet class, one that (like AbstractQueue) implements all methods by throwing UnsupportedOperationException (Eclipse autogenerates these methods in a split second).
  • Now extend AbstractResultSet. The subclass can override only the methods you're interested in implementing.

Upvotes: 22

skaffman
skaffman

Reputation: 403461

This is a slightly left-field solution, but you could make use of a mocking framework (e.g. JMock). These frameworks are generally intended for creating mock implementations of interfaces for unit testing, but I see no reason why you could use one to create a "partial implementation" of java.sql.ResultSet.

For example, say you only wanted to implement the getString() method, and nothing else:

Mockery mockery = new Mockery();
final ResultSet resultSet = mockery.mock(ResultSet.class);

mockery.checking(new Expectations() {{
    allowing(resultSet).getString(1); will(returnValue("my first string"));
    allowing(resultSet).getString(2); will(returnValue("my second string"));
}});

// resultSet is now a java.sql.ResultSet object, which you can pass to your legacy code
resultSet.getString(1);

Rather unorthodox, and quite cumbersome, but it should work

Upvotes: 12

alex
alex

Reputation: 5201

My first option would be to refactor the code so that it takes List<Map<String,Object>> or something appropriate (that is, List<Map<String,Object>> if the data being moved around has no real structure or fully-typed objects if it does have structure).

If that's not feasible or time efficient, the "fun" hack is to query an in-memory H2 database to get a ResultSet. If you don't find a reasonable stub for ResultSet you can easily instantiate, it might be quicker than rolling your own (pull the jar in, write 20 lines of code for creating the db and populating a table).

Upvotes: 3

rayd09
rayd09

Reputation: 1897

java.sql.ResultSet is an interface, so you could create your own class that implements that interface.

Upvotes: 1

Nathan Wheeler
Nathan Wheeler

Reputation: 5932

I don't normally answer java questions, as I'm not a java developer, but this seems like an architectural flaw if you need to create a sql object from code to pass into a method in order to recycle a method. I would think you would want to make your receiving method accept some other more specific form of input (such as a custom defined object array) to make it reusable, and then parse your ResultData into that format.

Upvotes: 0

davek
davek

Reputation: 22905

You could take a look at the CachedRowSet interface:

http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/rowset/CachedRowSet.html

which allows you work in disconnected mode.

Upvotes: 4

Related Questions