0

I faced with following problem in 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);
    }
}

I tried to search and found that after getting testDomainObj it is the instance of Object class. So, it is clear that deserialized object loses its metainformation.

I configured JdbcOperationsSessionRepository like this:

@Configuration
public class AppConfig {
    @Bean
    SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
        return new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
    }
}

And activated it in application.properties:

spring.session.store-type=jdbc
spring.session.jdbc.initializer.enabled=true

Last thing testDomain object has been saved in Database after executing sessionRepository.save(session);

How to understand and cope with this problem?

Alex Po
  • 1,837
  • 1
  • 24
  • 28
  • Wouldn't `TestDomain testDomain1 = session1.getAttribute(session1.getId());` work? – Lance Toth Feb 27 '18 at 09:48
  • Firstly I tried this but I got ClassCastException such as when I am casting `Object testDomain1` to `TestDomain` class above – Alex Po Feb 27 '18 at 10:02
  • Could this help? https://stackoverflow.com/questions/826319/classcastexception-when-casting-to-the-same-class – Lance Toth Feb 27 '18 at 10:10

2 Answers2

1

You're encountering this problem because you register JdbcOperationsSessionRepository bean manually rather than reusing Spring Session JDBC configuration facilities, i.e. @EnableJdbcHttpSession. See the relevant code in JdbcHttpSessionConfiguration.

Spring Boot makes this even easier by providing auto-configuration support for Spring Session so you don't even need to use @EnableJdbcHttpSession. Simply adding spring.session.store-type=jdbc to configuration properties takes care of everything for you.

Vedran Pavic
  • 2,339
  • 2
  • 27
  • 31
0

Well, I answer on my question. In my case I should specify ClassLoader for the deserializer like this:

@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;
}
Alex Po
  • 1,837
  • 1
  • 24
  • 28