If you are not a JDBC provider, it is not practical to implement interfaces such as this.
Consider using a proxy to ensure compatibility in JVM versions.
The transition to the proxy is as follows. Consider this implementation of ResultSet :
public class ResultSetFoo implements ResultSet { public String getString(int columnIndex) throws SQLException { return "foobar"; }
This will be changed, so no classes implement ResultSet :
public class ResultBar { public String getString(int columnIndex) throws SQLException { return "foobar"; }
Then you will need to build a method mapping between the two types at runtime (primitive form of duck input :)
private static final Map RESULT_SET_DUCK = initResultSet(); private static Map initResultSet() { Map map = new HashMap(); Method[] methods = ResultSet.class.getMethods(); for (int i = 0; i < methods.length; i++) { try { Method match = ResultBar.class.getMethod(methods[i].getName(), methods[i].getParameterTypes()); map.put(methods[i], match); } catch (SecurityException e) { throw new IllegalStateException(e); } catch (NoSuchMethodException e) {
This allows you to call the ResultBar type by proxy:
public static ResultSet proxy(final ResultBar duck) { class Handler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method proxiedMethod = (Method) RESULT_SET_DUCK.get(method); if (proxiedMethod == null) { throw new UnsupportedOperationException("TODO: method detail"); } else { return invoke(proxiedMethod, duck, args); } } private Object invoke(Method m, Object target, Object[] args) throws Throwable { try { return m.invoke(target, args); } catch (InvocationTargetException e) { throw e.getCause(); } } } return (ResultSet) Proxy.newProxyInstance(null, RSET, new Handler()); }
Such implementations should allow code compiled in one JVM to be used in future JVMs, even if new methods are added. Existing method signatures are unlikely to change, because one thing is that database manufacturers do some work; something else to change all API users.
You may need to change the way you instantiate the class. You can no longer use the constructor directly:
ResultSet nonPortable = new ResultSetFoo(); //becomes... ResultSet portable = proxy(new ResultBar());
If you are already using factory / builder / etc. this bit pattern is simple.
Although the reflection in cheap JVMs is relatively cheap, it is less in older versions. this may adversely affect performance.