Spring-boot-devtools that throws a ClassCastException when getting from the cache.

I ran into a problem while getting value from cache.

java.lang.RuntimeException: java.lang.ClassCastException: com.mycom.admin.domain.User cannot be cast to com.mycom.admin.domain.User 

Cache configuration

 @Configuration @EnableCaching @AutoConfigureAfter(value = { MetricsConfiguration.class, DatabaseConfiguration.class }) @Profile("!" + Constants.SPRING_PROFILE_FAST) public class MemcachedCacheConfiguration extends CachingConfigurerSupport { private final Logger log = LoggerFactory.getLogger(MemcachedCacheConfiguration.class); @Override @Bean public CacheManager cacheManager() { ExtendedSSMCacheManager cacheManager = new ExtendedSSMCacheManager(); try { List<SSMCache> list = new ArrayList<>(); list.add(new SSMCache(defaultCache("apiCache"), 86400, false)); cacheManager.setCaches(list); } catch (Exception e) { e.printStackTrace(); } return cacheManager; } @Override public CacheResolver cacheResolver() { return null; } @Override public CacheErrorHandler errorHandler() { return null; } private Cache defaultCache(String cacheName) throws Exception { CacheFactory cacheFactory = new CacheFactory(); cacheFactory.setCacheName(cacheName); cacheFactory.setCacheClientFactory(new MemcacheClientFactoryImpl()); String serverHost = "127.0.0.1:11211"; cacheFactory.setAddressProvider(new DefaultAddressProvider(serverHost)); cacheFactory.setConfiguration(cacheConfiguration()); return cacheFactory.getObject(); } @Bean public CacheConfiguration cacheConfiguration() { CacheConfiguration cacheConfiguration = new CacheConfiguration(); cacheConfiguration.setConsistentHashing(true); return cacheConfiguration; } } 

And annotated with

 @Cacheable(value = "apiCache#86400", key = "'User-'.concat(#login)") 

I am using com.google.code.simple- spring -memcached 3.5.0

The value gets cached, but when receiving the application throws the cast class to the class. What would be the possible problems.

Full stack trace

+6
source share
3 answers

This is a well-known limitation of Devtools . When the cache entry is descripted, the object is not bound to the corresponding class loader.

There are various solutions to this problem:

  • Disable cache when starting an application in development
  • Use a different cache manager (if you are using Spring Boot 1.3, you can force the simple cache manager to use the spring.cache.type property in application-dev.properties and enable the dev profile in your IDE)
  • Configure memcached (and everything that is cached) to run in the application class loader . I would not recommend this option, since the first two above are much easier to implement.
+8
source

Well, I got the same error, but caching was not the reason. I actually used caching, but commenting on caching did not help.

Based on the prompts here and there, I just introduced the extra serialization / derivation of my object. This is definitely the best way (performance issue), but it works.

So, just for the rest, I changed my code:

 @Cacheable("tests") public MyDTO loadData(String testID) { // add file extension to match XML file return (MyDTO) this.xmlMarshaller.loadXML(String.format("%s/%s.xml", xmlPath, testID)); } 

in

 @Cacheable("tests") public MyDTO loadData(String testID) { // add file extension to match XML file Object dtoObject = this.xmlMarshaller.loadXML(String.format("%s/%s.xml", xmlPath, testID)); byte[] data = serializeDTO(dtoObject); MyDTO dto = deserializeDTO(data); return dto; } private MyDTO deserializeDTO(byte[] data) { MyDTO dto = null; try { ByteArrayInputStream fileIn = new ByteArrayInputStream(data); ObjectInputStream in = new ConfigurableObjectInputStream(fileIn, Thread.currentThread().getContextClassLoader()); dto = (MyDTO) in.readObject(); in.close(); fileIn.close(); } catch (Exception e) { String msg = "Deserialization of marshalled XML failed!"; LOG.error(msg, e); throw new RuntimeException(msg, e); } return dto; } private byte[] serializeDTO(Object dtoObject) { byte[] result = null; try { ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(data); out.writeObject(dtoObject); out.close(); result = data.toByteArray(); data.close(); } catch (IOException e) { String msg = "Serialization of marshalled XML failed!"; LOG.error(msg, e); throw new RuntimeException(msg, e); } return result; } 

Note: this is not some complicated solution, but just a hint of using the ConfigurableObjectInputStream class.

+1
source

I encountered the same problem when starting a project in Eclipse with the STS plugin enabled. Although I completely removed the devtools dependency from the project. It was still included in the eclipse. To fix this, I had to disable devtools.

enter image description here

0
source

All Articles