The issue I am facing is that two objects returned from spring cacheable method with a same key fail assertSame test. Why are these objects not sharing one same storage area?
Details: I am using redis cache mechanism to implement caching in a spring boot REST api. The caching works correctly in the way that it first retrieve the data from externally provided source (JPS repository accessing a database) and then subsequent calls for the same cache key returns data from cache. However, I am not able to mimic this behavior completely in the JUnit test cases. My assertEquals or assertSame fail on 2 objects returned from the cache.
my code base looks as below: mvn dependencies:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.6.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Spring application config:
@SpringBootApplication
@EnableCaching
public class Application {
@Value("${redis.host}")
private String redisHost;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
jedisConFactory.setHostName(redisHost);
jedisConFactory.setPort(6379);
return jedisConFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
@Bean
CacheManager cacheManager() {
return new RedisCacheManager(redisTemplate());
}
Service Class:
@Service
public class CIDomainService {
private RedisTemplate<String, Object> redisTemplate;
private CIDomainDAO ciDomainDAO;
@Autowired
public CIDomainService(CIDomainDAO ciDomainDAO, RedisTemplate<String, Object> redisTemplate) {
this.ciDomainDAO = ciDomainDAO;
this.redisTemplate = redisTemplate;
}
@Cacheable(value = "ciDomain", key = "#id")
public CIDomain getCIDomain(int id) {
CIDomain ciDomain = new CIDomain();
ciDomain.setId(id);
ciDomain.setName("SomeName");
return ciDomain;
}
public void clearAllCache() {
redisTemplate.delete("listCIDomains");
redisTemplate.delete("ciDomain");
}
}
ciDomainDAO in the service above is just a JPS repository interface using the findAll() method to retrieve data from external database or in-memory database. My Test class:
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("local")
@SpringBootTest
public class CIDomainServiceIntegrationTest {
@Autowired
CIDomainService ciDomainServiceSpy;
@Before
public void setUp(){
ciDomainServiceSpy.clearAllCache();
}
@Test
public void listCIDomains_ShouldRetrieveCIDomainsWithCachingPluggedIn() {
CIDomain domain1 = ciDomainServiceSpy.getCIDomain(1);
CIDomain domain2 = ciDomainServiceSpy.getCIDomain(2);
CIDomain domain3 = ciDomainServiceSpy.getCIDomain(1);
assertSame(domain1, domain3); //fails
}
My Domain Class:
@Entity
@Table(name = "CI_DOMAIN")
public class CIDomain implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
based on this post I understand that object is retrieved from the repository for the very first call and then later call will fetch this object from cache provided same "key" is provided. I am doing the same thing in my test case above but assertSame is failing. Spring cacheable must be caching object in memory which is fetched for a given request. Why would it send different objects everytime for the same requested key.
I have tried to have an alternative solution where I used spy on the service class and verify method calls based on a same key request. However, I encountered different issues in doing that. Creating a spy on the service class does not even use caching mechanism and it does call service getCIDomain method even if same key is provided. I followed this, this, this, this, this and lots of other posts for further analysis but could not get it working either through assertSame of spy.
Any help would really be appreciated.