Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Message Serialization: Enhance deserialization #688

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

AZCodingAccount
Copy link

Background

Hey there, while developing with Spring Boot, I encountered issues with Jackson deserialization when storing historical messages into the Redis client. After troubleshooting using the control variable method, I found that there is room for improvement in the classes under the Message package. I made two code modifications to accommodate the new version of Jackson's deserialization process.

Solution

  1. I added no-argument constructors to UserMessage, SystemMessage, FunctionMessage, and AssistMessage, and modified AbstractMessage to include a single-argument constructor. This resolves the following serialization error:
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `org.springframework.ai.chat.messages.SystemMessage` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
  1. I renamed textContent and mediaData in AbstractMessage to content and media to align with the methods exposed by the message. This change can resolve the following error:
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Problem deserializing 'setterless' property ("media"): no way to handle typed deser with setterless yet

PS: Additional Information

Version Information: Spring Boot 3.2.4, spring-boot-starter-data-redis 3.2.4, SpringAI 1.0.0-SNAPSHOT

RedisTemplateConfig.java:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<Object> serializer = redisSerializer();
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedisSerializer<Object> redisSerializer() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        return new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant