diff --git a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java index 759df031..50d1c1dd 100644 --- a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java +++ b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2017 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.session.jdbc.config.annotation.web.http; import java.util.Map; @@ -20,6 +21,7 @@ import java.util.Map; import javax.sql.DataSource; import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.EmbeddedValueResolverAware; @@ -33,14 +35,11 @@ import org.springframework.core.convert.support.GenericConversionService; import org.springframework.core.serializer.support.DeserializingConverter; import org.springframework.core.serializer.support.SerializingConverter; import org.springframework.core.type.AnnotationMetadata; -import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.lob.LobHandler; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; import org.springframework.session.jdbc.JdbcOperationsSessionRepository; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; @@ -78,17 +77,17 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration private StringValueResolver embeddedValueResolver; - @Bean - public JdbcTemplate springSessionJdbcOperations(DataSource dataSource) { - return new JdbcTemplate(dataSource); - } - @Bean public JdbcOperationsSessionRepository sessionRepository( - @Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations, + @SpringSessionDataSource ObjectProvider springSessionDataSource, + ObjectProvider dataSource, PlatformTransactionManager transactionManager) { - JdbcOperationsSessionRepository sessionRepository = - new JdbcOperationsSessionRepository(jdbcOperations, transactionManager); + DataSource dataSourceToUse = springSessionDataSource.getIfAvailable(); + if (dataSourceToUse == null) { + dataSourceToUse = dataSource.getObject(); + } + JdbcOperationsSessionRepository sessionRepository = new JdbcOperationsSessionRepository( + dataSourceToUse, transactionManager); String tableName = getTableName(); if (StringUtils.hasText(tableName)) { sessionRepository.setTableName(tableName); @@ -104,7 +103,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration else if (this.conversionService != null) { sessionRepository.setConversionService(this.conversionService); } - else if (deserializingConverterSupportsCustomClassLoader()) { + else { GenericConversionService conversionService = createConversionServiceWithBeanClassLoader(); sessionRepository.setConversionService(conversionService); } @@ -115,7 +114,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration * This must be a separate method because some ClassLoaders load the entire method * definition even if an if statement guards against it loading. This means that older * versions of Spring would cause a NoSuchMethodError if this were defined in - * {@link #sessionRepository(JdbcOperations, PlatformTransactionManager)}. + * {@link #sessionRepository(ObjectProvider, ObjectProvider, PlatformTransactionManager)}. * * @return the default {@link ConversionService} */ @@ -163,10 +162,6 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration return this.tableName; } - private boolean deserializingConverterSupportsCustomClassLoader() { - return ClassUtils.hasConstructor(DeserializingConverter.class, ClassLoader.class); - } - public void setImportMetadata(AnnotationMetadata importMetadata) { Map enableAttrMap = importMetadata .getAnnotationAttributes(EnableJdbcHttpSession.class.getName()); @@ -192,4 +187,5 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } + } diff --git a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/SpringSessionDataSource.java b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/SpringSessionDataSource.java new file mode 100644 index 00000000..db45f842 --- /dev/null +++ b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/SpringSessionDataSource.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2017 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 + * + * http://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.session.jdbc.config.annotation.web.http; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.session.jdbc.JdbcOperationsSessionRepository; + +/** + * Qualifier annotation for a {@link DataSource} to be injected in + * {@link JdbcOperationsSessionRepository}. + * + * @author Vedran Pavic + * @since 2.0.0 + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier +public @interface SpringSessionDataSource { + +} diff --git a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java index 99105c13..0e9e3d0a 100644 --- a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java +++ b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2017 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. @@ -23,12 +23,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.convert.ConversionService; +import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.support.lob.LobHandler; import org.springframework.mock.env.MockEnvironment; import org.springframework.session.jdbc.JdbcOperationsSessionRepository; @@ -67,10 +69,10 @@ public class JdbcHttpSessionConfigurationTests { @Test public void noDataSourceConfiguration() { - this.thrown.expect(UnsatisfiedDependencyException.class); - this.thrown.expectMessage("springSessionJdbcOperations"); + this.thrown.expect(BeanCreationException.class); + this.thrown.expectMessage("sessionRepository"); - registerAndRefresh(EmptyConfiguration.class); + registerAndRefresh(NoDataSourceConfiguration.class); } @Test @@ -145,6 +147,78 @@ public class JdbcHttpSessionConfigurationTests { .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); } + @Test + public void qualifiedDataSourceConfiguration() { + registerAndRefresh(QualifiedDataSourceConfiguration.class); + + JdbcOperationsSessionRepository repository = this.context + .getBean(JdbcOperationsSessionRepository.class); + DataSource dataSource = this.context.getBean("qualifiedDataSource", DataSource.class); + assertThat(repository).isNotNull(); + assertThat(dataSource).isNotNull(); + JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils + .getField(repository, "jdbcOperations"); + assertThat(jdbcOperations).isNotNull(); + assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource")) + .isEqualTo(dataSource); + } + + @Test + public void primaryDataSourceConfiguration() { + registerAndRefresh(PrimaryDataSourceConfiguration.class); + + JdbcOperationsSessionRepository repository = this.context + .getBean(JdbcOperationsSessionRepository.class); + DataSource dataSource = this.context.getBean("primaryDataSource", DataSource.class); + assertThat(repository).isNotNull(); + assertThat(dataSource).isNotNull(); + JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils + .getField(repository, "jdbcOperations"); + assertThat(jdbcOperations).isNotNull(); + assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource")) + .isEqualTo(dataSource); + } + + @Test + public void qualifiedAndPrimaryDataSourceConfiguration() { + registerAndRefresh(QualifiedAndPrimaryDataSourceConfiguration.class); + + JdbcOperationsSessionRepository repository = this.context + .getBean(JdbcOperationsSessionRepository.class); + DataSource dataSource = this.context.getBean("qualifiedDataSource", DataSource.class); + assertThat(repository).isNotNull(); + assertThat(dataSource).isNotNull(); + JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils + .getField(repository, "jdbcOperations"); + assertThat(jdbcOperations).isNotNull(); + assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource")) + .isEqualTo(dataSource); + } + + @Test + public void namedDataSourceConfiguration() { + registerAndRefresh(NamedDataSourceConfiguration.class); + + JdbcOperationsSessionRepository repository = this.context + .getBean(JdbcOperationsSessionRepository.class); + DataSource dataSource = this.context.getBean("dataSource", DataSource.class); + assertThat(repository).isNotNull(); + assertThat(dataSource).isNotNull(); + JdbcOperations jdbcOperations = (JdbcOperations) ReflectionTestUtils + .getField(repository, "jdbcOperations"); + assertThat(jdbcOperations).isNotNull(); + assertThat(ReflectionTestUtils.getField(jdbcOperations, "dataSource")) + .isEqualTo(dataSource); + } + + @Test + public void multipleDataSourceConfiguration() { + this.thrown.expect(BeanCreationException.class); + this.thrown.expectMessage("sessionRepository"); + + registerAndRefresh(MultipleDataSourceConfiguration.class); + } + @Test public void customLobHandlerConfiguration() { registerAndRefresh(CustomLobHandlerConfiguration.class); @@ -188,13 +262,13 @@ public class JdbcHttpSessionConfigurationTests { @Configuration @EnableJdbcHttpSession - static class EmptyConfiguration { + static class NoDataSourceConfiguration { } static class BaseConfiguration { @Bean - public DataSource dataSource() { + public DataSource defaultDataSource() { return mock(DataSource.class); } @@ -239,6 +313,70 @@ public class JdbcHttpSessionConfigurationTests { extends BaseConfiguration { } + @Configuration + @EnableJdbcHttpSession + static class QualifiedDataSourceConfiguration extends BaseConfiguration { + + @Bean + @SpringSessionDataSource + public DataSource qualifiedDataSource() { + return mock(DataSource.class); + } + + } + + @Configuration + @EnableJdbcHttpSession + static class PrimaryDataSourceConfiguration extends BaseConfiguration { + + @Bean + @Primary + public DataSource primaryDataSource() { + return mock(DataSource.class); + } + + } + + @Configuration + @EnableJdbcHttpSession + static class QualifiedAndPrimaryDataSourceConfiguration extends BaseConfiguration { + + @Bean + @SpringSessionDataSource + public DataSource qualifiedDataSource() { + return mock(DataSource.class); + } + + @Bean + @Primary + public DataSource primaryDataSource() { + return mock(DataSource.class); + } + + } + + @Configuration + @EnableJdbcHttpSession + static class NamedDataSourceConfiguration extends BaseConfiguration { + + @Bean + public DataSource dataSource() { + return mock(DataSource.class); + } + + } + + @Configuration + @EnableJdbcHttpSession + static class MultipleDataSourceConfiguration extends BaseConfiguration { + + @Bean + public DataSource secondaryDataSource() { + return mock(DataSource.class); + } + + } + @Configuration @EnableJdbcHttpSession static class CustomLobHandlerConfiguration extends BaseConfiguration {