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

Parsing case insensitive enums #209

Closed
joserobjr opened this issue Sep 7, 2018 · 20 comments
Closed

Parsing case insensitive enums #209

joserobjr opened this issue Sep 7, 2018 · 20 comments
Labels

Comments

@joserobjr
Copy link

How can we parse case insensitive enums like we do on Jackson?

Example:

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JSON
import kotlin.test.Test
import kotlin.test.assertEquals

enum class SampleEnum {
    FOO, BAR
}

@Serializable
data class SampleData(val a: String, val b: SampleEnum)

class TestCase {
    private val expected = SampleData("value", SampleEnum.FOO)

    @Test
    fun testUpperCase() {
        assertEquals(expected,
                JSON.unquoted.parse("{a:value,b:FOO}"))
    }

    @Test
    fun testLowerCase() {
        assertEquals(expected,
                JSON.unquoted.parse("{a:value,b:foo}"))
    }
}

Result:

No enum constant SampleEnum.foo
java.lang.IllegalArgumentException: No enum constant SampleEnum.foo
	at java.lang.Enum.valueOf(Enum.java:238)
	at kotlinx.serialization.SerializationKt.enumFromName(Serialization.kt:28)
	at kotlinx.serialization.json.JSON$JsonInput.readEnumValue(JSON.kt:304)
	at kotlinx.serialization.internal.EnumSerializer.load(BuiltinSerializers.kt:115)
	at kotlinx.serialization.internal.EnumSerializer.load(BuiltinSerializers.kt:112)
	at kotlinx.serialization.KInput.readSerializableValue(Serialization.kt:245)
	at kotlinx.serialization.ElementValueInput.readSerializableElementValue(Serialization.kt:440)
	at SampleData$$serializer.load(sample.kt)
	at SampleData$$serializer.load(sample.kt:11)
	at kotlinx.serialization.KInput.read(Serialization.kt:211)
	at kotlinx.serialization.json.JSON.parse(JSON.kt:42)
	at TestCase.testLowerCase(sample.kt:30)
@sandwwraith
Copy link
Member

sandwwraith commented Sep 12, 2018

Can this issue be treated as the more specific version of #33 ?

@henningBunk
Copy link

@sandwwraith it does not seem that #33 gets implemented. Would this issue have a bigger chance on it's own?

@sandwwraith
Copy link
Member

@henningBunk Perhaps, but I hope we would be able to implement #33 in one of the following releases

@mecoFarid
Copy link

What @JakeWharton implied in #33 is "this probably won't happen"

@sandwwraith
Copy link
Member

See #2111 (comment)

@AndyOHart
Copy link

@sandwwraith Just wondering if this is the same thing this issue is talking about, but I have some json coming back like this:
"state":"bad",

I want to parse that into an ENUM class, which will have BAD, GOOD, NEAR_GOOD.
Is this currently possible or is this what the bug is talking about?
Right now I have

@Serializable internal enum class State() { @SerialName("good") GOOD, @SerialName("bad") BAD, @SerialName("near_good") NEAR_GOOD }

However I see when it gets parsed, it is parsed as BAD, but I want it to match the json and be lowercase.
Thanks!

@sandwwraith
Copy link
Member

It's about global configuration. Locally it is achievable with @SerialName or @JsonNames.

@AndyOHart
Copy link

Hey @sandwwraith, just getting back to this now.
So with the example I gave, the server sends us 'bad' for example, I want to parse that and keep it as 'bad', but have the enum be BAD, since that is how the enum should look.
How can I achieve that based on what I sent above? Since I am already using @SerialName and it is changing the casing to uppercase

@sandwwraith
Copy link
Member

What do you mean by "keep it as 'bad"? @SerialName works both for encodeToString and decodeFromString

@AndyOHart
Copy link

@sandwwraith So in the example I gave, the server sends us "state":"bad" as JSON.
So I have a data class like this:

@Serializable
internal enum class State {
    @SerialName("good") GOOD,
    @SerialName("bad") BAD,
    @SerialName("near_good") NEAR_GOOD
}

Which will parse the JSON.
The issue I'm talking about is, I want to have this enum class show the vals as uppercase, as I have shown, which is how enums should be written.
The issue I have is, right now when we get back 'bad' from the server, it gets parsed as BAD, and is now lowercase.
So I am wondering is it possible to parsed the potential responses 'good|bad|near_good', but have the enum of it be uppercase.

Hope that makes sense.

@sandwwraith
Copy link
Member

I still don't get it, as you already have uppercase enum in Kotlin. Maybe you want to use @JsonNames instead of @SerialName, like this?

@Serializable
internal enum class State {
    @JsonNames("good") GOOD,
    @JsonNames("bad") BAD,
    @JsonNames("near_good") NEAR_GOOD
}

This will parse both bad and BAD and serialize enum as BAD string.

@AndyOHart
Copy link

@sandwwraith The way it is now, it is changing the JSON to show as BAD instead of reading it as 'bad'.
Essentially I want to be able to call:
State.GOOD, and have that return 'good'
Right now, it returns 'GOOD'.
I tried with @JsonNames and it still returned it as BAD instead of bad

@AndyOHart
Copy link

For example, this is what I see when I debug:
image
And it came from this JSON
image

@sandwwraith
Copy link
Member

Erm, do you know what enum class are and how's their toString() works?

@AndyOHart
Copy link

Not familiar with the internal toString of enums, but I understand enum class, but you are making me question that now :D
Could you elaborate? Sorry about bringing this up here but I thought this bug was regarding the issue I mentioned.

@sandwwraith
Copy link
Member

I suggest closing the conversation here, as it is entirely unrelated — what you see in the debugger and how enum classes are working in Kotlin is defined by Kotlin language, not by kotlinx.serialization. In short, their name and toString() return the actual enum member name as it is defined in your source file.

@AndyOHart
Copy link

AndyOHart commented Jan 16, 2023

Ok apologies, I understood this issue incorrectly, thought it Was related to my problem.
Thanks anyway

sandwwraith added a commit that referenced this issue Jun 21, 2023
It allows decoding enum values in a case-insensitive manner. It does not affect CLASS kinds or encoding. It is one of the most-voted feature requests.

Fixes #209
sandwwraith added a commit that referenced this issue Jun 22, 2023
It allows decoding enum values in a case-insensitive manner. It does not affect CLASS kinds or encoding. It is one of the most-voted feature requests.

Also enchance JsonNamingStrategy documentation.

Fixes #209
@leinardi
Copy link

This issue is open since 2018, there is still no solution to parse case insensitive enums?

@sandwwraith
Copy link
Member

@leinardi It's linked above: #2345. Expected to merge it in 1.6.0-RC.

@leinardi
Copy link

leinardi commented Jul 3, 2023

Oh sorry, I somehow missed that 🙈

Looking forward to test it!

JesusMcCloud pushed a commit to a-sit-plus/kotlinx.serialization that referenced this issue Jul 5, 2023
It allows decoding enum values in a case-insensitive manner. It does not affect CLASS kinds or encoding. It is one of the most-voted feature requests.

Also enhance JsonNamingStrategy documentation.

Fixes Kotlin#209
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants