From f5ecd3a9b10b2fc2fdd1fcfd4405ed93003ddb35 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 26 Apr 2016 08:39:17 +0200 Subject: [PATCH] DATAREDIS-501 - Use application context ClassLoader as default for JdkSerializationRedisSerializer in RedisTemplate. We now pick up the ClassLoader from the ApplicationContext and use the latter as default in RedisTemplate for initializing the JdkSerializationRedisSerializer. We only do this in case the default serializer has not been set explicitly. Original pull request: #192. --- .../data/redis/core/RedisTemplate.java | 29 ++++++++++++-- .../redis/core/RedisTemplateUnitTests.java | 38 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 7a9dcb9ad..f2b9677ce 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015 the original author or authors. + * Copyright 2011-2016 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. @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.RedisSystemException; @@ -75,13 +76,14 @@ import org.springframework.util.CollectionUtils; * @param the Redis value type against which the template works * @see StringRedisTemplate */ -public class RedisTemplate extends RedisAccessor implements RedisOperations { +public class RedisTemplate extends RedisAccessor implements RedisOperations, BeanClassLoaderAware { private boolean enableTransactionSupport = false; private boolean exposeConnection = false; private boolean initialized = false; private boolean enableDefaultSerializer = true; - private RedisSerializer defaultSerializer = new JdkSerializationRedisSerializer(); + private RedisSerializer defaultSerializer; + private ClassLoader classLoader; private RedisSerializer keySerializer = null; private RedisSerializer valueSerializer = null; @@ -104,10 +106,19 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation public RedisTemplate() {} public void afterPropertiesSet() { + super.afterPropertiesSet(); + boolean defaultUsed = false; + if (defaultSerializer == null) { + + defaultSerializer = new JdkSerializationRedisSerializer( + classLoader != null ? classLoader : this.getClass().getClassLoader()); + } + if (enableDefaultSerializer) { + if (keySerializer == null) { keySerializer = defaultSerializer; defaultUsed = true; @@ -1096,4 +1107,16 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation this.enableTransactionSupport = enableTransactionSupport; } + /** + * Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other + * {@link RedisSerializer} is explicitly set as the default one. + * + * @param resourceLoader can be {@literal null}. + * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader + * @since 1.8 + */ + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } } diff --git a/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java index 9102f6ef4..9806bcaa1 100644 --- a/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/RedisTemplateUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2016 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. @@ -15,9 +15,14 @@ */ package org.springframework.data.redis.core; +import static org.hamcrest.core.Is.*; +import static org.hamcrest.core.IsNull.*; +import static org.junit.Assert.*; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; +import java.io.Serializable; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,6 +30,8 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.instrument.classloading.ShadowingClassLoader; /** * @author Christoph Strobl @@ -32,14 +39,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; @RunWith(MockitoJUnitRunner.class) public class RedisTemplateUnitTests { - private RedisTemplate template; + private RedisTemplate template; private @Mock RedisConnectionFactory connectionFactoryMock; private @Mock RedisConnection redisConnectionMock; @Before public void setUp() { - template = new RedisTemplate(); + template = new RedisTemplate(); template.setConnectionFactory(connectionFactoryMock); when(connectionFactoryMock.getConnection()).thenReturn(redisConnectionMock); @@ -66,4 +73,29 @@ public class RedisTemplateUnitTests { verify(redisConnectionMock, times(1)).slaveOfNoOne(); } + /** + * @see DATAREDIS-501 + */ + @Test + public void templateShouldPassOnAndUseResoureLoaderClassLoaderToDefaultJdkSerializerWhenNotAlreadySet() { + + ShadowingClassLoader scl = new ShadowingClassLoader(ClassLoader.getSystemClassLoader()); + + template = new RedisTemplate(); + template.setConnectionFactory(connectionFactoryMock); + template.setBeanClassLoader(scl); + template.afterPropertiesSet(); + + when(redisConnectionMock.get(any(byte[].class))) + .thenReturn(new JdkSerializationRedisSerializer().serialize(new SomeArbitrarySeriaizableObject())); + + Object deserialized = template.opsForValue().get("spring"); + assertThat(deserialized, notNullValue()); + assertThat(deserialized.getClass().getClassLoader(), is((ClassLoader) scl)); + } + + static class SomeArbitrarySeriaizableObject implements Serializable { + private static final long serialVersionUID = -5973659324040506423L; + } + }