-
-
Notifications
You must be signed in to change notification settings - Fork 177
enum @JsonCreator method called with wrong parameter type when using customized visibility ObjectMapper #78
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
Comments
@cowtowncoder this seems to be something in databind since the kotlin module doesn't do anything with types. If it is handed a string as a parameter it uses a string as a parameter. This seems familiar and maybe related to the other reported issue here about enum not working with (this was one of the other issues, #75 ... but I remember this coming up a while ago as well in another older) |
I think the first step would be to double-check that this occurs with latest patch, 2.8.9. |
Just tried running the tests with 2.8.9, same result:
|
Thank you for verifying this. I'll create a new issue on databind, linking to this one -- I hope this is reproducible on pure Java version. |
Ok, I can not reproduce this with Java, but I do have one guess: could it be that Kotlin module might be recognizing factory method as property-based creator (one that maps by name), and not delegating one?
which would ensure correct mode is used. Question of why mode is detected is more complex and it's something that may or may not be fixable here -- but let's first figure out if this is the problem. |
Fwtw forcing mode |
@cowtowncoder I can confirm your guess. I ran into a similar issue when upgrading from Jackson 2.7.7 to 2.9.3. I didn't set any specific visibility configurations on the ObjectMapper. I did some debugging into Jackson's internals and it was, indeed, inferring enum class Test(val id: Int) {
A(10), B(20), C(30);
companion object {
@JsonCreator
@JvmStatic
fun findById(id: Int) = values().find { it.id == id }
}
} It appears that Jackson infers this mode when it matches the parameter name from findById ( From my perspective, it doesn't make sense at all to use |
@jose-cieni-movile It does sound like heuristics to figure out mode may have backfired here, but I think the solution really is to define mode explicitly for This wrt core Jackson databind: perhaps Kotlin module could try more elaborate handling. That'd be for @apatrida to comment. If it was me, I would add |
Is there any improvement on this issue? Both of the workarounds work in latest version but would be nice get this fixed. |
I seem to be having this issue with a pure Java application (no Kotlin). The |
Still very complicated to just parse a value as a string. Instead of just using the provided constructor (Kotlin) you still have to
Im mean, seriously, WTF?! Why not simply like this? enum class Quarters @JsonCreator constructor(val number: Number) {
ONE(1),
TWO(2),
THREE(3),
FOUR(4);
} |
@spyro2000 Since you know how to do that and how simple it is, maybe you can submit a fix? |
@spyro2000 That'd be a great contribution, make a PR and I'll give it a look. |
I commented out the import com.fasterxml.jackson.annotation.JsonAutoDetect
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class GitHub78 {
enum class JacksonTest(private val value: Int) {
TEST(0), TEST2(1);
companion object {
@JvmStatic @JsonCreator
fun fromInt(value: Int): JacksonTest {
return JacksonTest.entries.find { it.value == value } ?: TEST
}
}
}
enum class JacksonTest2(private val value: Int) {
TEST(0), TEST2(1);
companion object {
@JvmStatic @JsonCreator
fun fromInt(intValue: Int): JacksonTest2 {
return JacksonTest2.entries.find { it.value == intValue } ?: TEST
}
}
}
@Test
fun jacksonTest1_customMapper_fails() {
val mapper = jacksonObjectMapper()
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
mapper.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY)
val deserialized = mapper.readValue("1", JacksonTest::class.java) // throws exception
assertEquals(deserialized, JacksonTest.TEST2)
}
@Test
fun jacksonTest1_defaultMapper_succeeds() {
val mapper = jacksonObjectMapper()
val deserialized = mapper.readValue("1", JacksonTest::class.java)
assertEquals(deserialized, JacksonTest.TEST2)
}
@Test
fun jacksonTest2_customMapper_succeeds() {
val mapper = jacksonObjectMapper()
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) // works with or without this
mapper.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY) // works with or without this
val deserialized = mapper.readValue("1", JacksonTest2::class.java)
assertEquals(deserialized, JacksonTest2.TEST2)
}
@Test
fun jacksonTest2_defaultMapper_succeeds() {
val mapper = jacksonObjectMapper()
val deserialized = mapper.readValue("1", JacksonTest2::class.java)
assertEquals(deserialized, JacksonTest2.TEST2)
}
} |
I have a weird issue using
@JsonCreator
on enums, but only when using anObjectMapper
with customized visibility. Depending on the name of the parameters of the@JsonCreator
and constructor methods, the deserialization will fail or succeed. Tested using Jackson 2.8.7 with Kotlin 1.1.2, addingkotlin-reflect
or not does not change the results.Short snippet to reproduce the issue: those 2 classes are exactly the same, except for the name of
fromInt
parameter (JacksonTest
class uses the same name as the enum constructor, whileJacksonTest2
uses a different name)Then running the following tests, the first one fails when using custom visibility on ObjectMapper, but only when using
JacksonTest
enum, it works well withJacksonTest2
(which is exactly the same class, with just a renamed parameter):It seems that in the first case, when both parameters have the same name and ObjectMapper uses customized visibility, then Jackson tries to call that
@JsonCreator
method with a String parameter instead of an Int.But for some reason, if the parameters have different names, then everything is working as expected.
The text was updated successfully, but these errors were encountered: