FasterXML / FasterXML/jackson-module-kotlin
A `DatabindException` is thrown when processing a class that has a getter defined that is interpreted similarly to the property name of the `value class`
- Dominant language
- Kotlin
- Stars
- 1.2k
- Forks
- 187
- Avg merge
- 9h 48m
- Merged PRs (30d)
- 16
Description
### Search before asking
- [x] I searched in the [issues](https://github.com/FasterXML/jackson-module-kotlin/issues) and found nothing similar.
- [x] I have confirmed that the same problem is not reproduced if I exclude the KotlinModule.
- [x] I searched in the [issues of databind](https://github.com/FasterXML/jackson-databind/issues) and other modules used and found nothing similar.
- [ ] I have confirmed that the problem does not reproduce in Java and only occurs when using Kotlin and KotlinModule.
### Describe the bug
[side note]
> I have confirmed that the same problem is not reproduced if I exclude the KotlinModule.
I need to use Kotlin, so I don't see why I should exclude the module.
[/side note]
Hello.
I've a Kotlin library with some data classes which uses extensively the unsigned types.
For a better compatibility with Java, I defined additional getters for those fields that return the matching primitive type (e.g.: UShort -> int), but the library fails during the serialization.
My test case is as simple as
```kotlin
@ParameterizedTest
@ArgumentsSource(JsonMessagesArgumentsProvider::class)
fun `should handle JSON serialization and deserialization correctly (jackson)`(message: Mdf2Message) {
// given
val mapper = jacksonObjectMapper()
// when
val serialized = mapper.writeValueAsString(message)
// then
assertThat(serialized).isNotBlank()
// when
val deserialized = mapper.readValue>(serialized)
// then
assertThat(deserialized).isEqualTo(message)
}
```
and the error I get is:
```console
tools.jackson.databind.DatabindException: Conflicting getter definitions for property "bodyLength": com.foo.cit.fmd.mdf2.api.model.Mdf2Header#getBodyLength() vs com.foo.cit.fmd.mdf2.api.model.Mdf2Header#getBodyLength-Mh2AYeg()
at [No location information]
at tools.jackson.databind.DatabindException.from(DatabindException.java:73)
at tools.jackson.databind.SerializationContext._mappingProblem(SerializationContext.java:1391)
at tools.jackson.databind.SerializationContext._createAndCachePropertySerializer(SerializationContext.java:1051)
at tools.jackson.databind.SerializationContext.findPrimaryPropertySerializer(SerializationContext.java:703)
at tools.jackson.databind.ser.bean.BeanSerializerBase.resolve(BeanSerializerBase.java:311)
at tools.jackson.databind.ser.UnrolledBeanSerializer.resolve(UnrolledBeanSerializer.java:155)
at tools.jackson.databind.ser.SerializerCache.addAndResolveNonTypedSerializer(SerializerCache.java:238)
at tools.jackson.databind.SerializationContext._createAndCacheUntypedSerializer(SerializationContext.java:997)
at tools.jackson.databind.SerializationContext.findValueSerializer(SerializationContext.java:796)
at tools.jackson.databind.SerializationContext.findTypedValueSerializer(SerializationContext.java:592)
at tools.jackson.databind.ser.SerializationContextExt.serializeValue(SerializationContextExt.java:297)
at tools.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:1901)
at tools.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:1845)
at com.foo.cit.fmd.mdf2.api.model.Mdf2MessageTest$Json.should handle JSON serialization and deserialization correctly (jackson)(Mdf2MessageTest.kt:193)
Caused by: java.lang.IllegalArgumentException: Conflicting getter definitions for property "bodyLength": com.foo.cit.fmd.mdf2.api.model.Mdf2Header#getBodyLength() vs com.foo.cit.fmd.mdf2.api.model.Mdf2Header#getBodyLength-Mh2AYeg()
at tools.jackson.databind.introspect.POJOPropertyBuilder.getGetter(POJOPropertyBuilder.java:479)
at tools.jackson.databind.introspect.BeanPropertyDefinition.getAccessor(BeanPropertyDefinition.java:182)
at tools.jackson.databind.ser.BeanSerializerFactory.removeIgnorableTypes(BeanSerializerFactory.java:735)
at tools.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:564)
at tools.jackson.databind.ser.BeanSerializerFactory.constructBeanOrAddOnSerializer(BeanSerializerFactory.java:325)
at tools.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:249)
at tools.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:182)
at tools.jackson.databind.SerializationContext._createAndCachePropertySerializer(SerializationContext.java:1049)
... 11 more
```
The Kotlin bytecode of the conflicting method is:
```java
public final short getBodyLength_Mh2AYeg/* $FF was: getBodyLength-Mh2AYeg*/() {
return this.bodyLength;
}
public final int getBodyLength() {
return this.bodyLength & '\uffff';
}
```
### To Reproduce
```kotlin
// Additional fields removed for simplicity
data class Mdf2Header(
val bodyLength: UShort
) {
val sizeBytes: UShort = 20u
@JvmOverloads
constructor(
bodyLength: Int
): this(bodyLength.toUShort())
init {
require(bodyLength > UShort.MIN_VALUE) { "The passed length is for the entire message and it has therefore be bigger than $sizeBytes" }
}
fun getBodyLength() = bodyLength.toInt()
}
```
### Expected behavior
It should ideally work and pick the proper synthetic getter when an unsigned type is used.
Maybe the type of the field should be inspected and, if it's an unsigned type / value class, pick the getter that in the `@Metadata` annotation is called `get-`.
### Versions
Kotlin: 2.3.20
Jackson-module-kotlin: 3.1.2
Jackson-databind: 3.1.2
Java: 25
### Additional context
https://youtrack.jetbrains.com/issue/KT-85796/Expose-unsigned-types-value-classes-to-Java
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.