Describe the bug
When using Spring Security's Jackson deserialization with Kotlin, there's a bug in how Mixin classes are applied to primitive wrapper classes. In Java, when applying a Mixin to Long.class
, the key is correctly set to "java.lang.Long". However, in Kotlin, the equivalent code results in the key being set to lowercase "long", causing allowlist configurations to fail.
Caused by: java.lang.IllegalArgumentException: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details
at org.springframework.security.jackson2.SecurityJackson2Modules$AllowlistTypeIdResolver.typeFromId(SecurityJackson2Modules.java:293) ~[spring-security-core-6.4.3.jar:6.4.3]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:159) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:100) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:56) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:238) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializerNR.deserializeWithType(UntypedObjectDeserializerNR.java:112) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:625) ~[jackson-databind-2.18.2.jar:2.18.2]
... 16 common frames omitted
To Reproduce
1. Create a Spring Boot application using Kotlin
2. Configure Jackson ObjectMapper with Security modules
3. Try to add a Mixin for Long.class
using addMixIn(Long::class.java, LongMixin::class.java)
4. Observe that the Mixin is registered with key "long" instead of "java.lang.Long"
Expected behavior
When adding a Mixin in Kotlin using addMixIn(Long::class.java, LongMixin::class.java)
, the key should be set to "java.lang.Long" just like in Java, not lowercase "long".
Sample Java code (working correctly):
@JsonMixin(Long.class)
abstract class LongMixin {}
public void customObjectMapper(ObjectMapper objectMapper) {
ObjectMapper copied = objectMapper.copy();
copied.registerModules(SecurityJackson2Modules.getModules(this.classLoader));
copied.addMixIn(Long.class, LongMixin.class);
// Mixin key is set to "java.lang.Long"
}
Kotlin code (exhibiting the bug):
@JsonMixin(Long::class)
abstract class LongMixin {}
fun customObjectMapper(objectMapper: ObjectMapper) {
val copied: ObjectMapper = objectMapper.copy()
copied.registerModules(SecurityJackson2Modules.getModules(this.classLoader))
copied.addMixIn(Long::class.java, LongMixin::class.java)
// Mixin key is incorrectly set to "long" instead of "java.lang.Long"
}
I'm not entirely sure if this is the right place to report this issue, so I apologize if I've posted it in the wrong location.