3

When you use spring-session-jdbc, the sessions are serialized in DB as bytes, which means you have to drop all sessions every time you upgrade Spring to a version with incompatible Session.serialVersionUUID.

I wanted to store the session in JSON format but after some googling it seems like nobody has ever done this.

This is weird when you consider that storing sessions in Redis using JSON is common practice.

Why isn't there a standard way to store sessions in JDBC in JSON format? And how could this be achieved?

Jardo
  • 1,939
  • 2
  • 25
  • 45

1 Answers1

1

The main problem with JSON is object types: you can easily serialize objects as JSON, but when it comes to deserializing - you can never know what type of object this JSON respresents.

I've faced with kind of same problem. But it was enough for me to parse only the part of JSON data, which comes to session from external source. My solution was to create two new implementations of org.springframework.core.convert.converter.Converter interface - one for serializing (Object to byte[]) and one for deserializing (byte[] to Object), and then register them as converters for Spring. This converters are used by org.springframework.session.jdbc.JdbcOperationsSessionRepository to store/read session attributes bytes. You can create your implementations like so (used Jackson library to work with JSON):

JsonSerializingConverter

@Component
public class JsonSerializingConverter implements Converter<Object, byte[]> {
    @Override
    public byte[] convert(Object source) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsBytes(source);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

JsonDeserializingConverter

@Component
public class JsonDeserializingConverter implements Converter<byte[], Object> {
    @Override
    public Object convert(byte[] source) {
       ObjectMapper objectMapper = new ObjectMapper();
       try {
         return objectMapper.readValue(source, Object.class);
       } catch (IOException e) {
         e.printStackTrace();
       }
       return null;
    }
}

Next you should register them:

@Configuration
public class ConversionServiceConfiguration
{
    @Bean
    public ConversionServiceFactoryBean conversionService()
    {
        ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
        bean.setConverters(getConverters());

        return bean;
    }

    private Set<Converter> getConverters()
    {
        Set<Converter> converters = new HashSet<>();
        converters.add(new JsonDeserializingConverter());
        converters.add(new JsonSerializingConverter());

        return converters;
    }
}

It will work fine unless you don't need to bind JSON data with object (for example CsrfToken object). In such case, you probably can annotate your JSON string with target type on serializing step, and deserialize into that type on deserialization step. Hope this might help.

cheeseq
  • 79
  • 1
  • 9