Avoid a hard dependency on Sun's CachedRowSetImpl class

Also using the JDBC 4.1 RowSetProvider API directly instead of going through reflection, since we're building on JDK 7 now.
This commit is contained in:
Juergen Hoeller 2012-11-25 22:20:25 +01:00
parent e2f418ab4c
commit 9e337d2705
1 changed files with 55 additions and 21 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2011 the original author or authors. * Copyright 2002-2012 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,20 +16,21 @@
package org.springframework.jdbc.core; package org.springframework.jdbc.core;
import java.lang.reflect.Method;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import javax.sql.rowset.CachedRowSet; import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetFactory;
import javax.sql.rowset.RowSetProvider;
import com.sun.rowset.CachedRowSetImpl; import com.sun.rowset.CachedRowSetImpl;
import org.springframework.core.JdkVersion;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet; import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.util.ReflectionUtils;
/** /**
* ResultSetExtractor implementation that returns a Spring SqlRowSet * {@link ResultSetExtractor} implementation that returns a Spring {@link SqlRowSet}
* representation for each given ResultSet. * representation for each given {@link ResultSet}.
* *
* <p>The default implementation uses a standard JDBC CachedRowSet underneath. * <p>The default implementation uses a standard JDBC CachedRowSet underneath.
* This means that JDBC RowSet support needs to be available at runtime: * This means that JDBC RowSet support needs to be available at runtime:
@ -45,20 +46,16 @@ import org.springframework.util.ReflectionUtils;
*/ */
public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet> { public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet> {
private static Object rowSetFactory = null; private static final CachedRowSetFactory cachedRowSetFactory;
private static Method createCachedRowSet = null;
static { static {
ClassLoader cl = SqlRowSetResultSetExtractor.class.getClassLoader(); if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_17) {
try { // using JDBC 4.1 RowSetProvider
Class rowSetProviderClass = cl.loadClass("javax.sql.rowset.RowSetProvider"); cachedRowSetFactory = new StandardCachedRowSetFactory();
Method newFactory = rowSetProviderClass.getMethod("newFactory");
rowSetFactory = ReflectionUtils.invokeMethod(newFactory, null);
createCachedRowSet = rowSetFactory.getClass().getMethod("createCachedRowSet");
} }
catch (Exception ex) { else {
// JDBC 4.1 API not available - fall back to Sun CachedRowSetImpl // JDBC 4.1 API not available - fall back to Sun CachedRowSetImpl
cachedRowSetFactory = new SunCachedRowSetFactory();
} }
} }
@ -88,19 +85,56 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
/** /**
* Create a new CachedRowSet instance, to be populated by * Create a new CachedRowSet instance, to be populated by
* the <code>createSqlRowSet</code> implementation. * the <code>createSqlRowSet</code> implementation.
* <p>The default implementation creates a new instance of * <p>The default implementation uses JDBC 4.1's RowSetProvider
* Sun's <code>com.sun.rowset.CachedRowSetImpl</code> class. * when running on JDK 7 or higher, falling back to Sun's
* <code>com.sun.rowset.CachedRowSetImpl</code> class on older JDKs.
* @return a new CachedRowSet instance * @return a new CachedRowSet instance
* @throws SQLException if thrown by JDBC methods * @throws SQLException if thrown by JDBC methods
* @see #createSqlRowSet * @see #createSqlRowSet
* @see com.sun.rowset.CachedRowSetImpl * @see com.sun.rowset.CachedRowSetImpl
*/ */
protected CachedRowSet newCachedRowSet() throws SQLException { protected CachedRowSet newCachedRowSet() throws SQLException {
if (createCachedRowSet != null) { return cachedRowSetFactory.createCachedRowSet();
// RowSetProvider.newFactory().createCachedRowSet(); }
return (CachedRowSet) ReflectionUtils.invokeJdbcMethod(createCachedRowSet, rowSetFactory);
/**
* Internal strategy interface for the creation of CachedRowSet instances.
*/
private interface CachedRowSetFactory {
CachedRowSet createCachedRowSet() throws SQLException;
}
/**
* Inner class to avoid a hard dependency on JDBC 4.1 RowSetProvider class.
*/
private static class StandardCachedRowSetFactory implements CachedRowSetFactory {
private final RowSetFactory rowSetFactory;
public StandardCachedRowSetFactory() {
try {
this.rowSetFactory = RowSetProvider.newFactory();
}
catch (SQLException ex) {
throw new IllegalStateException("Cannot create RowSetFactory through RowSetProvider", ex);
}
} }
else {
public CachedRowSet createCachedRowSet() throws SQLException {
return this.rowSetFactory.createCachedRowSet();
}
}
/**
* Inner class to avoid a hard dependency on Sun's CachedRowSetImpl class.
*/
private static class SunCachedRowSetFactory implements CachedRowSetFactory {
public CachedRowSet createCachedRowSet() throws SQLException {
return new CachedRowSetImpl(); return new CachedRowSetImpl();
} }
} }