diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlRowSetResultSetExtractor.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlRowSetResultSetExtractor.java index ba62017d27..82d78739fc 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlRowSetResultSetExtractor.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/SqlRowSetResultSetExtractor.java @@ -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"); * you may not use this file except in compliance with the License. @@ -16,20 +16,21 @@ package org.springframework.jdbc.core; -import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.rowset.CachedRowSet; +import javax.sql.rowset.RowSetFactory; +import javax.sql.rowset.RowSetProvider; import com.sun.rowset.CachedRowSetImpl; +import org.springframework.core.JdkVersion; import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet; import org.springframework.jdbc.support.rowset.SqlRowSet; -import org.springframework.util.ReflectionUtils; /** - * ResultSetExtractor implementation that returns a Spring SqlRowSet - * representation for each given ResultSet. + * {@link ResultSetExtractor} implementation that returns a Spring {@link SqlRowSet} + * representation for each given {@link ResultSet}. * *

The default implementation uses a standard JDBC CachedRowSet underneath. * 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 { - private static Object rowSetFactory = null; - - private static Method createCachedRowSet = null; + private static final CachedRowSetFactory cachedRowSetFactory; static { - ClassLoader cl = SqlRowSetResultSetExtractor.class.getClassLoader(); - try { - Class rowSetProviderClass = cl.loadClass("javax.sql.rowset.RowSetProvider"); - Method newFactory = rowSetProviderClass.getMethod("newFactory"); - rowSetFactory = ReflectionUtils.invokeMethod(newFactory, null); - createCachedRowSet = rowSetFactory.getClass().getMethod("createCachedRowSet"); + if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_17) { + // using JDBC 4.1 RowSetProvider + cachedRowSetFactory = new StandardCachedRowSetFactory(); } - catch (Exception ex) { + else { // JDBC 4.1 API not available - fall back to Sun CachedRowSetImpl + cachedRowSetFactory = new SunCachedRowSetFactory(); } } @@ -88,19 +85,56 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractorcreateSqlRowSet implementation. - *

The default implementation creates a new instance of - * Sun's com.sun.rowset.CachedRowSetImpl class. + *

The default implementation uses JDBC 4.1's RowSetProvider + * when running on JDK 7 or higher, falling back to Sun's + * com.sun.rowset.CachedRowSetImpl class on older JDKs. * @return a new CachedRowSet instance * @throws SQLException if thrown by JDBC methods * @see #createSqlRowSet * @see com.sun.rowset.CachedRowSetImpl */ protected CachedRowSet newCachedRowSet() throws SQLException { - if (createCachedRowSet != null) { - // RowSetProvider.newFactory().createCachedRowSet(); - return (CachedRowSet) ReflectionUtils.invokeJdbcMethod(createCachedRowSet, rowSetFactory); + return cachedRowSetFactory.createCachedRowSet(); + } + + + /** + * 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(); } }