-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Question: DefaultTyping and java records/kotlin data classes #4636
Comments
No; addition of But note that deprecation will not mean dropping of the option during 2.x -- it will remain. As to better mechanism: to me, use of simple wrapper makes sense to completely avoid Default Typing usage:
this will add type information for every |
thanks for the feedback, and thanks for taking the time to provide an alternative |
@cowtowncoder can you provide a full example of how to generically use the wrapper to avoid Default Typing usage? |
@dannywils I included example above:
and you'd create wrapped value, serialize/deserialize it as expected with If you have specific question, please elaborate. I don't know your usage or expectations. |
@cowtowncoder I’ll elaborate on my question. In my case, similar to the original poster, I’m using the RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(
fromSerializer(
GenericJackson2JsonRedisSerializer(
objectMapper
)
)
) The @Cacheable
fun getAll(): Set<MyCustomDataClass>
@Cacheable
fun getSingle(): MyCustomDataClass Using val objectMapper = jacksonObjectMapper()
.activateDefaultTyping(
jacksonObjectMapper().polymorphicTypeValidator,
// activating EVERYTHING on default typing, otherwise deserialization results in `LinkedHashMap`,
// or fails due to Kotlin data classes being final.
ObjectMapper.DefaultTyping.EVERYTHING,
JsonTypeInfo.As.PROPERTY
) But, val objectMapper = jacksonObjectMapper() // no default typing
data class Wrapper (
@JsonTypeInfo(use= JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property=“class”)
val value: Any
)
@Cacheable
fun getAll(): Wrapper // wraps Set<MyCustomDataClass>
@Cacheable
fun getSingle(): Wrapper // wraps MyCustomDataClass Or are you suggesting something different? |
You don't need to modify all your Cachable sites. You can just wrap the object you're serializing in the Serializer implementation. |
I am not familiar with the package, or use of |
We also just ran into this problem using So I'm using a simple public class JsonRedisSerializer implements RedisSerializer<Object>
{
private final ObjectMapper objectMapper;
public JsonRedisSerializer()
{
this.objectMapper = getObjectMapper();
}
static ObjectMapper getObjectMapper()
{
return JsonMapper.builder()
// other options here
.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL_AND_ENUMS,
JsonTypeInfo.As.WRAPPER_ARRAY)
.build();
}
@Override
public byte[] serialize(Object t) throws SerializationException
{
try {
return objectMapper.writeValueAsBytes(t);
} catch (JsonProcessingException e) {
throw new SerializationException(e.getMessage(), e);
}
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException
{
if (bytes == null) {
return null;
}
try {
return objectMapper.readValue(bytes, Object.class);
} catch (Exception e) {
throw new SerializationException(e.getMessage(), e);
}
}
} Would having a I understand the wrapper workaround, however, it is not backward compatible so it would involve a lengthy migration or a cache key prefix change which is not always feasable. TIA! |
I would like to avoid changes to If anything, it'd be nice to make it easier to have custom definitions, since needs vary a lot. But I do not have concrete ideas of how that could work. Aside from that, I wonder what'd happen with something like:
|
maybe this helps, use a custom RedisSerializer, wrap value when serialize, and check value type when deserialize to ensure compatibility open class Wrapper(
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "class")
val value: Any? = null
)
class WrapperGenericJackson2JsonRedisSerializer(mapper: ObjectMapper) : GenericJackson2JsonRedisSerializer(mapper) {
override fun serialize(value: Any?): ByteArray {
var tempValue = value
if (value != null) {
if (Modifier.isFinal(value.javaClass.modifiers)) {
tempValue = Wrapper(value)
}
}
return super.serialize(tempValue)
}
override fun deserialize(source: ByteArray?): Any {
val wrapper = super.deserialize(source)
return if (wrapper is Wrapper) {
wrapper.value!!
} else {
wrapper
}
}
} |
Describe your Issue
Java records are final, as well as Kotlin data classes; in version 2.17,
DefaultTyping
deprecates theEVERYTHING
option (from #4160), however there are legit use cases to keep it, ie: when generic deserialization is needed for framework integration.Is it possible to reverse the decision an "undeprecate"
DefaultTyping.EVERYTHING
?For instance, in the following example (Kotlin because I got used to Kotlin, but I think the same applies to Java records too), using Redis in combination spring-data-redis as a cache, I could achieve proper generic deserialization only by using
DefaultTyping.EVERYTHING
.Disclaimer: there might another way to get generic deserialization working, I experimented for a while and could only come up with this, but in no way I claim that this is the only solution.
Please also let me know if you think this is better addressed in Spring/Redis, to be honest I think something might be improved there to achieve the same result
The text was updated successfully, but these errors were encountered: