数据库对象持久化后反序列化无法转换为源 Class: ClassCastException: TestDomain 无法转换为 TestDomain
Deserialized after persistence in Database object can't be casted into source Class: ClassCastException: TestDomain cannot be cast to TestDomain
我在 spring-session
中遇到了以下问题:
@RestController
public class TestService {
@Autowired
private SessionRepository sessionRepository;
@GetMapping("/test")
public void test() {
Session session = sessionRepository.createSession();
TestDomain testDomain = new TestDomain("a", 1);
session.setAttribute(session.getId(), testDomain);
sessionRepository.save(session);
Session session1 = sessionRepository.getSession(session.getId());
Object testDomainObj = session1.getAttribute(session1.getId());
// I wonder why TestDomainObj is not an instance of TestDomain??
System.out.println("Does testDomainObj from session represent the instance of TestDomain class: " + (testDomainObj instanceof TestDomain));
// java.lang.ClassCastException: com.example.demo.TestDomain cannot be cast to com.example.demo.TestDomain
TestDomain testDomain1 = (TestDomain) testDomainObj;
System.out.println(testDomain1);
}
}
我试着搜索了一下,得到testDomainObj
后发现是Objectclass的实例。因此,很明显反序列化的对象丢失了它的元信息。
我这样配置 JdbcOperationsSessionRepository
:
@Configuration
public class AppConfig {
@Bean
SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
return new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
}
}
并在 application.properties
中激活它:
spring.session.store-type=jdbc
spring.session.jdbc.initializer.enabled=true
最后一件事 testDomain
对象在执行 sessionRepository.save(session);
后已保存在数据库中
如何理解和应对这个问题?
好吧,我回答我的问题。在我的例子中,我应该像这样为反序列化器指定 ClassLoader:
@Bean
SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
JdbcOperationsSessionRepository sessionRepository = new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(Object.class, byte[].class,
new SerializingConverter());
conversionService.addConverter(byte[].class, Object.class,
new DeserializingConverter(Thread.currentThread().getContextClassLoader()));
sessionRepository.setConversionService(conversionService);
return sessionRepository;
}
您遇到此问题是因为您手动注册了 JdbcOperationsSessionRepository
bean,而不是重复使用 Spring 会话 JDBC 配置工具,即 @EnableJdbcHttpSession
。参见 the relevant code in JdbcHttpSessionConfiguration
。
Spring Boot 通过为 Spring Session 提供 auto-configuration 支持使这变得更加容易,因此您甚至不需要使用 @EnableJdbcHttpSession
。只需将 spring.session.store-type=jdbc
添加到配置属性即可为您处理一切。
我在 spring-session
中遇到了以下问题:
@RestController
public class TestService {
@Autowired
private SessionRepository sessionRepository;
@GetMapping("/test")
public void test() {
Session session = sessionRepository.createSession();
TestDomain testDomain = new TestDomain("a", 1);
session.setAttribute(session.getId(), testDomain);
sessionRepository.save(session);
Session session1 = sessionRepository.getSession(session.getId());
Object testDomainObj = session1.getAttribute(session1.getId());
// I wonder why TestDomainObj is not an instance of TestDomain??
System.out.println("Does testDomainObj from session represent the instance of TestDomain class: " + (testDomainObj instanceof TestDomain));
// java.lang.ClassCastException: com.example.demo.TestDomain cannot be cast to com.example.demo.TestDomain
TestDomain testDomain1 = (TestDomain) testDomainObj;
System.out.println(testDomain1);
}
}
我试着搜索了一下,得到testDomainObj
后发现是Objectclass的实例。因此,很明显反序列化的对象丢失了它的元信息。
我这样配置 JdbcOperationsSessionRepository
:
@Configuration
public class AppConfig {
@Bean
SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
return new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
}
}
并在 application.properties
中激活它:
spring.session.store-type=jdbc
spring.session.jdbc.initializer.enabled=true
最后一件事 testDomain
对象在执行 sessionRepository.save(session);
如何理解和应对这个问题?
好吧,我回答我的问题。在我的例子中,我应该像这样为反序列化器指定 ClassLoader:
@Bean
SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
JdbcOperationsSessionRepository sessionRepository = new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(Object.class, byte[].class,
new SerializingConverter());
conversionService.addConverter(byte[].class, Object.class,
new DeserializingConverter(Thread.currentThread().getContextClassLoader()));
sessionRepository.setConversionService(conversionService);
return sessionRepository;
}
您遇到此问题是因为您手动注册了 JdbcOperationsSessionRepository
bean,而不是重复使用 Spring 会话 JDBC 配置工具,即 @EnableJdbcHttpSession
。参见 the relevant code in JdbcHttpSessionConfiguration
。
Spring Boot 通过为 Spring Session 提供 auto-configuration 支持使这变得更加容易,因此您甚至不需要使用 @EnableJdbcHttpSession
。只需将 spring.session.store-type=jdbc
添加到配置属性即可为您处理一切。