33

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.

1

8 Answers 8

22
  • 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.
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I ended up going this route. The AbstractResultSet class is a nice layer to use for the noise of all the throw statements, and the final implementation class can contain only meaningful code.
12

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

Comments

4

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.

Comments

4

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.

Comments

3

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

1 Comment

Agreed, that's what I was trying to get at in java terms. +1
1

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

3 Comments

He explicitly said that implementing ResultSet is a ton of work (it really is).
It would be if your are trying to achieve all of the functionality of the database specific ResultSet classes, but if you are only attempting to mimic a ResultSet for some specific cases then it shouldn't be difficult at all. It is like he said. He could ignore most of the methods.
I'd recommend implementing only the methods you need (YAGNI)
0

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.

3 Comments

Oops... i meant `ResultSet', and it's an interface rather than a concrete class, so I thought that'd be okay. The ResultSet can be pretty variable in its content, so making a List<SomeType> seemed to be not the best choice.
I can think of many good reasons to create an empty (e.g. mocked) result set. We do this all the time with all sorts of other library types, including collections. ResultSet is no different, except that it's quite difficult to implement / mock correctly.
@LukasEder - The idea here is that you're transforming an object or set of data into a completely different type. If you needed to create a mock ResultSet to see if your data retrieval was working correctly, that would be one thing, but specifically, this operation is going in reverse of that as it has been asked - taking results, parsing them into a useable dataset, then reversing that into a ResultSet again in order to accommodate a method that was written to accept a ResultSet. Ideally, you would want to pass your data around in the simplest form and not transform it more than needed.
0

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"}}
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.