Jakarta EE 9 migration
Upgrades many dependency declarations; removes old EJB 2.x support and outdated Servlet-based integrations (Commons FileUpload, FreeMarker JSP support, Tiles). Closes gh-22093 Closes gh-25354 Closes gh-26185 Closes gh-27423 See gh-27424
This commit is contained in:
@@ -52,14 +52,14 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <p>Application code is required to retrieve the JDBC Connection via
|
||||
* {@link DataSourceUtils#getConnection(DataSource)} instead of a standard
|
||||
* Java EE-style {@link DataSource#getConnection()} call. Spring classes such as
|
||||
* Jakarta EE-style {@link DataSource#getConnection()} call. Spring classes such as
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate} use this strategy implicitly.
|
||||
* If not used in combination with this transaction manager, the
|
||||
* {@link DataSourceUtils} lookup strategy behaves exactly like the native
|
||||
* DataSource lookup; it can thus be used in a portable fashion.
|
||||
*
|
||||
* <p>Alternatively, you can allow application code to work with the standard
|
||||
* Java EE-style lookup pattern {@link DataSource#getConnection()}, for example for
|
||||
* Jakarta EE-style lookup pattern {@link DataSource#getConnection()}, for example for
|
||||
* legacy code that is not aware of Spring at all. In that case, define a
|
||||
* {@link TransactionAwareDataSourceProxy} for your target DataSource, and pass
|
||||
* that proxy DataSource to your DAOs, which will automatically participate in
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
|
||||
* connection pool, implementing the same standard interface, but creating new
|
||||
* Connections on every call.
|
||||
*
|
||||
* <p>Useful for test or standalone environments outside of a Java EE container, either
|
||||
* <p>Useful for test or standalone environments outside of a Jakarta EE container, either
|
||||
* as a DataSource bean in a corresponding ApplicationContext or in conjunction with
|
||||
* a simple JNDI environment. Pool-assuming {@code Connection.close()} calls will
|
||||
* simply close the Connection, so any DataSource-aware persistence code should work.
|
||||
@@ -44,7 +44,7 @@ import org.springframework.util.ClassUtils;
|
||||
* loading issues with the JDBC DriverManager that be resolved through direct Driver
|
||||
* usage (which is exactly what SimpleDriverDataSource does).</b>
|
||||
*
|
||||
* <p>In a Java EE container, it is recommended to use a JNDI DataSource provided by
|
||||
* <p>In a Jakarta EE container, it is recommended to use a JNDI DataSource provided by
|
||||
* the container. Such a DataSource can be exposed as a DataSource bean in a Spring
|
||||
* ApplicationContext via {@link org.springframework.jndi.JndiObjectFactoryBean},
|
||||
* for seamless switching to and from a local DataSource bean like this class.
|
||||
|
||||
@@ -57,7 +57,7 @@ import org.springframework.lang.Nullable;
|
||||
* without paying a performance penalty if no actual data access happens.
|
||||
*
|
||||
* <p>This DataSource proxy gives you behavior analogous to JTA and a
|
||||
* transactional JNDI DataSource (as provided by the Java EE server), even
|
||||
* transactional JNDI DataSource (as provided by the Jakarta EE server), even
|
||||
* with a local transaction strategy like DataSourceTransactionManager or
|
||||
* HibernateTransactionManager. It does not add value with Spring's
|
||||
* JtaTransactionManager as transaction strategy.
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.util.Assert;
|
||||
* connection pool, implementing the same standard interface, but creating new
|
||||
* Connections on every call.
|
||||
*
|
||||
* <p>In a Java EE container, it is recommended to use a JNDI DataSource provided by
|
||||
* <p>In a Jakarta EE container, it is recommended to use a JNDI DataSource provided by
|
||||
* the container. Such a DataSource can be exposed as a DataSource bean in a Spring
|
||||
* ApplicationContext via {@link org.springframework.jndi.JndiObjectFactoryBean},
|
||||
* for seamless switching to and from a local DataSource bean like this class.
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
/**
|
||||
* Proxy for a target JDBC {@link javax.sql.DataSource}, adding awareness of
|
||||
* Spring-managed transactions. Similar to a transactional JNDI DataSource
|
||||
* as provided by a Java EE server.
|
||||
* as provided by a Jakarta EE server.
|
||||
*
|
||||
* <p>Data access code that should remain unaware of Spring's data access support
|
||||
* can work with this proxy to seamlessly participate in Spring-managed transactions.
|
||||
@@ -52,7 +52,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* Connection. If not within a transaction, normal DataSource behavior applies.
|
||||
*
|
||||
* <p>This proxy allows data access code to work with the plain JDBC API and still
|
||||
* participate in Spring-managed transactions, similar to JDBC code in a Java EE/JTA
|
||||
* participate in Spring-managed transactions, similar to JDBC code in a Jakarta EE/JTA
|
||||
* environment. However, if possible, use Spring's DataSourceUtils, JdbcTemplate or
|
||||
* JDBC operation objects to get transaction participation even without a proxy for
|
||||
* the target DataSource, avoiding the need to define such a proxy in the first place.
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link DataSource} implementation that delegates all calls to a WebSphere
|
||||
* target {@link DataSource}, typically obtained from JNDI, applying a current
|
||||
* isolation level and/or current user credentials to every Connection obtained
|
||||
* from it.
|
||||
*
|
||||
* <p>Uses IBM-specific API to get a JDBC Connection with a specific isolation
|
||||
* level (and read-only flag) from a WebSphere DataSource
|
||||
* (<a href="https://publib.boulder.ibm.com/infocenter/wasinfo/v5r1//topic/com.ibm.websphere.base.doc/info/aes/ae/rdat_extiapi.html">IBM code example</a>).
|
||||
* Supports the transaction-specific isolation level exposed by
|
||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionIsolationLevel()}.
|
||||
* It's also possible to specify a default isolation level, to be applied when the
|
||||
* current Spring-managed transaction does not define a specific isolation level.
|
||||
*
|
||||
* <p>Usage example, defining the target DataSource as an inner-bean JNDI lookup
|
||||
* (of course, you can link to any WebSphere DataSource through a bean reference):
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="myDataSource" class="org.springframework.jdbc.datasource.WebSphereDataSourceAdapter">
|
||||
* <property name="targetDataSource">
|
||||
* <bean class="org.springframework.jndi.JndiObjectFactoryBean">
|
||||
* <property name="jndiName" value="jdbc/myds"/>
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* Thanks to Ricardo Olivieri for submitting the original implementation
|
||||
* of this approach!
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author <a href="mailto:lari.hotari@sagire.fi">Lari Hotari</a>
|
||||
* @author <a href="mailto:roliv@us.ibm.com">Ricardo N. Olivieri</a>
|
||||
* @since 2.0.3
|
||||
* @see com.ibm.websphere.rsadapter.JDBCConnectionSpec
|
||||
* @see com.ibm.websphere.rsadapter.WSDataSource#getConnection(com.ibm.websphere.rsadapter.JDBCConnectionSpec)
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionIsolationLevel()
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
|
||||
*/
|
||||
public class WebSphereDataSourceAdapter extends IsolationLevelDataSourceAdapter {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Class<?> wsDataSourceClass;
|
||||
|
||||
private Method newJdbcConnSpecMethod;
|
||||
|
||||
private Method wsDataSourceGetConnectionMethod;
|
||||
|
||||
private Method setTransactionIsolationMethod;
|
||||
|
||||
private Method setReadOnlyMethod;
|
||||
|
||||
private Method setUserNameMethod;
|
||||
|
||||
private Method setPasswordMethod;
|
||||
|
||||
|
||||
/**
|
||||
* This constructor retrieves the WebSphere JDBC connection spec API,
|
||||
* so we can get obtain specific WebSphere Connections using reflection.
|
||||
*/
|
||||
public WebSphereDataSourceAdapter() {
|
||||
try {
|
||||
this.wsDataSourceClass = getClass().getClassLoader().loadClass("com.ibm.websphere.rsadapter.WSDataSource");
|
||||
Class<?> jdbcConnSpecClass = getClass().getClassLoader().loadClass("com.ibm.websphere.rsadapter.JDBCConnectionSpec");
|
||||
Class<?> wsrraFactoryClass = getClass().getClassLoader().loadClass("com.ibm.websphere.rsadapter.WSRRAFactory");
|
||||
this.newJdbcConnSpecMethod = wsrraFactoryClass.getMethod("createJDBCConnectionSpec");
|
||||
this.wsDataSourceGetConnectionMethod =
|
||||
this.wsDataSourceClass.getMethod("getConnection", jdbcConnSpecClass);
|
||||
this.setTransactionIsolationMethod =
|
||||
jdbcConnSpecClass.getMethod("setTransactionIsolation", int.class);
|
||||
this.setReadOnlyMethod = jdbcConnSpecClass.getMethod("setReadOnly", Boolean.class);
|
||||
this.setUserNameMethod = jdbcConnSpecClass.getMethod("setUserName", String.class);
|
||||
this.setPasswordMethod = jdbcConnSpecClass.getMethod("setPassword", String.class);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not initialize WebSphereDataSourceAdapter because WebSphere API classes are not available: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified 'targetDataSource' actually is
|
||||
* a WebSphere WSDataSource.
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
if (!this.wsDataSourceClass.isInstance(getTargetDataSource())) {
|
||||
throw new IllegalStateException(
|
||||
"Specified 'targetDataSource' is not a WebSphere WSDataSource: " + getTargetDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a WebSphere JDBCConnectionSpec object for the current settings
|
||||
* and calls {@code WSDataSource.getConnection(JDBCConnectionSpec)}.
|
||||
* @see #createConnectionSpec
|
||||
* @see com.ibm.websphere.rsadapter.WSDataSource#getConnection(com.ibm.websphere.rsadapter.JDBCConnectionSpec)
|
||||
*/
|
||||
@Override
|
||||
protected Connection doGetConnection(@Nullable String username, @Nullable String password) throws SQLException {
|
||||
// Create JDBCConnectionSpec using current isolation level value and read-only flag.
|
||||
Object connSpec = createConnectionSpec(
|
||||
getCurrentIsolationLevel(), getCurrentReadOnlyFlag(), username, password);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Obtaining JDBC Connection from WebSphere DataSource [" +
|
||||
getTargetDataSource() + "], using ConnectionSpec [" + connSpec + "]");
|
||||
}
|
||||
// Create Connection through invoking WSDataSource.getConnection(JDBCConnectionSpec)
|
||||
Connection con = (Connection) invokeJdbcMethod(
|
||||
this.wsDataSourceGetConnectionMethod, obtainTargetDataSource(), connSpec);
|
||||
Assert.state(con != null, "No Connection");
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WebSphere {@code JDBCConnectionSpec} object for the given characteristics.
|
||||
* <p>The default implementation uses reflection to apply the given settings.
|
||||
* Can be overridden in subclasses to customize the JDBCConnectionSpec object
|
||||
* (<a href="https://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/topic/com.ibm.websphere.javadoc.doc/public_html/api/com/ibm/websphere/rsadapter/JDBCConnectionSpec.html">JDBCConnectionSpec javadoc</a>;
|
||||
* <a href="https://www.ibm.com/developerworks/websphere/library/techarticles/0404_tang/0404_tang.html">IBM developerWorks article</a>).
|
||||
* @param isolationLevel the isolation level to apply (or {@code null} if none)
|
||||
* @param readOnlyFlag the read-only flag to apply (or {@code null} if none)
|
||||
* @param username the username to apply ({@code null} or empty indicates the default)
|
||||
* @param password the password to apply (may be {@code null} or empty)
|
||||
* @throws SQLException if thrown by JDBCConnectionSpec API methods
|
||||
* @see com.ibm.websphere.rsadapter.JDBCConnectionSpec
|
||||
*/
|
||||
protected Object createConnectionSpec(@Nullable Integer isolationLevel, @Nullable Boolean readOnlyFlag,
|
||||
@Nullable String username, @Nullable String password) throws SQLException {
|
||||
|
||||
Object connSpec = invokeJdbcMethod(this.newJdbcConnSpecMethod, null);
|
||||
Assert.state(connSpec != null, "No JDBCConnectionSpec");
|
||||
if (isolationLevel != null) {
|
||||
invokeJdbcMethod(this.setTransactionIsolationMethod, connSpec, isolationLevel);
|
||||
}
|
||||
if (readOnlyFlag != null) {
|
||||
invokeJdbcMethod(this.setReadOnlyMethod, connSpec, readOnlyFlag);
|
||||
}
|
||||
// If the username is empty, we'll simply let the target DataSource
|
||||
// use its default credentials.
|
||||
if (StringUtils.hasLength(username)) {
|
||||
invokeJdbcMethod(this.setUserNameMethod, connSpec, username);
|
||||
invokeJdbcMethod(this.setPasswordMethod, connSpec, password);
|
||||
}
|
||||
return connSpec;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static Object invokeJdbcMethod(Method method, @Nullable Object target, @Nullable Object... args)
|
||||
throws SQLException {
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
ReflectionUtils.handleReflectionException(ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof SQLException) {
|
||||
throw (SQLException) ex.getTargetException();
|
||||
}
|
||||
ReflectionUtils.handleInvocationTargetException(ex);
|
||||
}
|
||||
throw new IllegalStateException("Should never get here");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,13 +23,13 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import jakarta.transaction.RollbackException;
|
||||
import jakarta.transaction.Status;
|
||||
import jakarta.transaction.SystemException;
|
||||
import jakarta.transaction.Transaction;
|
||||
import jakarta.transaction.TransactionManager;
|
||||
import jakarta.transaction.UserTransaction;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
Reference in New Issue
Block a user