Utilize container's classloader

Resolves #15
This commit is contained in:
Greg Turnquist
2018-07-31 19:19:02 -05:00
parent bc59817693
commit b2dfa69b3d
6 changed files with 204 additions and 3 deletions

View File

@@ -15,16 +15,22 @@
*/
package org.springframework.session.data.mongo.config.annotation.web.http;
import java.time.Duration;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@@ -39,12 +45,13 @@ import org.springframework.util.StringValueResolver;
*/
@Configuration
public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements EmbeddedValueResolverAware, ImportAware {
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
private AbstractMongoSessionConverter mongoSessionConverter;
private Integer maxInactiveIntervalInSeconds;
private String collectionName;
private StringValueResolver embeddedValueResolver;
private ClassLoader classLoader;
@Bean
public MongoOperationsSessionRepository mongoSessionRepository(MongoOperations mongoOperations) {
@@ -54,6 +61,12 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
if (this.mongoSessionConverter != null) {
repository.setMongoSessionConverter(this.mongoSessionConverter);
} else {
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
new SerializingConverter(),
new DeserializingConverter(this.classLoader),
Duration.ofSeconds(MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL));
repository.setMongoSessionConverter(mongoSessionConverter);
}
if (StringUtils.hasText(this.collectionName)) {
@@ -89,6 +102,12 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio
this.mongoSessionConverter = mongoSessionConverter;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}

View File

@@ -15,17 +15,24 @@
*/
package org.springframework.session.data.mongo.config.annotation.web.reactive;
import java.time.Duration;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
import org.springframework.session.data.mongo.ReactiveMongoOperationsSessionRepository;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@@ -38,7 +45,7 @@ import org.springframework.util.StringValueResolver;
*/
@Configuration
public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfiguration
implements EmbeddedValueResolverAware, ImportAware {
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {
private AbstractMongoSessionConverter mongoSessionConverter;
private Integer maxInactiveIntervalInSeconds;
@@ -47,6 +54,7 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
@Autowired(required = false)
private MongoOperations mongoOperations;
private ClassLoader classLoader;
@Bean
public ReactiveMongoOperationsSessionRepository reactiveMongoOperationsSessionRepository(ReactiveMongoOperations operations) {
@@ -55,6 +63,12 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
if (this.mongoSessionConverter != null) {
repository.setMongoSessionConverter(this.mongoSessionConverter);
} else {
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
new SerializingConverter(),
new DeserializingConverter(this.classLoader),
Duration.ofSeconds(ReactiveMongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL));
repository.setMongoSessionConverter(mongoSessionConverter);
}
if (this.maxInactiveIntervalInSeconds != null) {
@@ -92,6 +106,11 @@ public class ReactiveMongoWebSessionConfiguration extends SpringWebSessionConfig
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver embeddedValueResolver) {
this.embeddedValueResolver = embeddedValueResolver;

View File

@@ -0,0 +1,70 @@
/*
* Copyright 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
*
* 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.data.mongo.integration;
import static org.assertj.core.api.AssertionsForClassTypes.*;
import java.lang.reflect.Field;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
import org.springframework.session.data.mongo.JdkMongoSessionConverter;
import org.springframework.util.ReflectionUtils;
/**
* Verify container's {@link ClassLoader} is injected into session converter (reactive and traditional).
*
* @author Greg Turnquist
*/
public abstract class AbstractClassLoaderTest<T> extends AbstractITest {
@Autowired
T sessionRepository;
@Autowired
ApplicationContext applicationContext;
@Test
public void verifyContainerClassLoaderLoadedIntoConverter() {
Field mongoSessionConverterField = ReflectionUtils.findField(sessionRepository.getClass(), "mongoSessionConverter");
ReflectionUtils.makeAccessible(mongoSessionConverterField);
AbstractMongoSessionConverter sessionConverter = (AbstractMongoSessionConverter) ReflectionUtils.getField(mongoSessionConverterField, this.sessionRepository);
assertThat(sessionConverter).isInstanceOf(JdkMongoSessionConverter.class);
JdkMongoSessionConverter jdkMongoSessionConverter = (JdkMongoSessionConverter) sessionConverter;
Field converterField = ReflectionUtils.findField(JdkMongoSessionConverter.class, "deserializer");
ReflectionUtils.makeAccessible(converterField);
DeserializingConverter deserializingConverter = (DeserializingConverter) ReflectionUtils.getField(converterField, jdkMongoSessionConverter);
Field deserializerField = ReflectionUtils.findField(DeserializingConverter.class, "deserializer");
ReflectionUtils.makeAccessible(deserializerField);
DefaultDeserializer deserializer = (DefaultDeserializer) ReflectionUtils.getField(deserializerField, deserializingConverter);
Field classLoaderField = ReflectionUtils.findField(DefaultDeserializer.class, "classLoader");
ReflectionUtils.makeAccessible(classLoaderField);
ClassLoader classLoader = (ClassLoader) ReflectionUtils.getField(classLoaderField, deserializer);
assertThat(classLoader).isEqualTo(applicationContext.getClassLoader());
}
}

View File

@@ -21,7 +21,6 @@ import java.time.Duration;
import java.util.Map;
import org.junit.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;

View File

@@ -0,0 +1,60 @@
/*
* Copyright 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
*
* 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.data.mongo.integration;
import java.io.IOException;
import de.flapdoodle.embed.mongo.MongodExecutable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.session.data.mongo.ReactiveMongoOperationsSessionRepository;
import org.springframework.session.data.mongo.config.annotation.web.reactive.EnableMongoWebSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.util.SocketUtils;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
/**
* @author Greg Turnquist
*/
@ContextConfiguration
public class ReactiveConfigurationTest extends AbstractClassLoaderTest<ReactiveMongoOperationsSessionRepository> {
@Configuration
@EnableMongoWebSession
static class Config {
private int embeddedMongoPort = SocketUtils.findAvailableTcpPort();
@Bean(initMethod = "start", destroyMethod = "stop")
public MongodExecutable embeddedMongoServer() throws IOException {
return MongoITestUtils.embeddedMongoServer(this.embeddedMongoPort);
}
@Bean
@DependsOn("embeddedMongoServer")
public ReactiveMongoOperations mongoOperations() {
MongoClient mongo = MongoClients.create("mongodb://localhost:" + this.embeddedMongoPort);
return new ReactiveMongoTemplate(mongo, "test");
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 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
*
* 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.data.mongo.integration;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
import org.springframework.session.data.mongo.integration.AbstractMongoRepositoryITest.BaseConfig;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Greg Turnquist
*/
@ContextConfiguration
public class TraditionalConfigurationTest extends AbstractClassLoaderTest<MongoOperationsSessionRepository> {
@Configuration
@EnableMongoHttpSession
static class Config extends BaseConfig {
}
}