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

Support deserialization in GenericJackson2JsonRedisSerializer when using custom JsonFactory #2981

Closed
housevenn opened this issue Aug 30, 2024 · 4 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@housevenn
Copy link

housevenn commented Aug 30, 2024

We create RedisCacheConfiguration with value serializer like this:

        RedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(new ObjectMapper(new MessagePackFactory()));
        RedisCacheConfiguration redisCacheConfig = RedisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer));

It uses an ObjectMapper with a custom JsonFactory (MessagePackFactory). Serialization works correctly, but deserialization encounters the following exception:

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('²' (code 178)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 1]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2643)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:685)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2750)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._nextTokenNotInObject(UTF8StreamJsonParser.java:867)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:753)
at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4934)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:3294)
at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer$TypeResolver.resolveType(GenericJackson2JsonRedisSerializer.java:363)
at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.resolveType(GenericJackson2JsonRedisSerializer.java:337)
at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:304)
at org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer.deserialize(GenericJackson2JsonRedisSerializer.java:276)
at com.coupang.storageservice.redis.spring.data.sdk.serializer.GzipRedisSerializer.deserialize(GzipRedisSerializer.java:54)
at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:46)
at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:277)
at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:386)
at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:209)

The error happens on this line at resolveType. The cause is that TypeResolver uses a default ObjectMapper which would throw exception here during deserialization when the value is serialized by our ObjectMapper with custom JsonFactory as shown above. The default ObjectMapper uses MappingJsonFactory in comparison.

Solution: when creating the TypeResolver here, we should use the ObjectMapper which was passed in here, and store it on the TypeResolver to use. Or at least make that an option so we can use it to avoid the deserialization error. I have tested that it can fix the deserialization issue, but not sure if there is any other implication.

FYI, our code was working fine with spring-data-redis 2.7.x but encountered this issue now as we are upgrading to spring-data-redis 3. It's because of this commit which changed the deserialization function and added resolveType.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 30, 2024
@mp911de
Copy link
Member

mp911de commented Sep 5, 2024

We're using a pristine ObjectMapper in TypeResolver as reading the type into JsonNode fails due to polymorphing typing restrictions.

I suggest that you explore options that let our test suite pass while you're able to address your issue.

@mp911de mp911de added status: ideal-for-contribution An issue that a contributor can help us with type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 5, 2024
@mp911de mp911de changed the title [Bug] GenericJackson2JsonRedisSerializer cannot deserialize values for ObjectMappers with custom JsonFactory Support deserialization in GenericJackson2JsonRedisSerializer when using custom JsonFactory Sep 5, 2024
@housevenn
Copy link
Author

housevenn commented Sep 13, 2024

Thanks for the explanation. So it looks like using ObjectMapper which has enabled typing (like this) will not work for type resolver, right?

Since our mapper does not enable it, it will still work. I am thinking we can expose a public function to support setting the custom mapper in type resolver (and add a comment that mappers which has enabled typing will not work).

I have a draft PR. I don't think it is a clean approach, but have not come up with a better alternative. Could you help take a look?

@mp911de
Copy link
Member

mp911de commented Sep 16, 2024

Thanks for looking into it. We indeed are looking for an approach that doesn't require additional configuration.

I created an approach by using JsonParser with JsonNodeDeserializer directly as alternative.

@mp911de mp911de self-assigned this Sep 16, 2024
@housevenn
Copy link
Author

Awesome. I have closed my draft PR and will wait for yours. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
4 participants