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

FieldRenamer overrides @Json name annotation #366

Open
vptp opened this issue Feb 19, 2024 · 0 comments
Open

FieldRenamer overrides @Json name annotation #366

vptp opened this issue Feb 19, 2024 · 0 comments

Comments

@vptp
Copy link

vptp commented Feb 19, 2024

Issue

The FieldRenamer currently overrides the field name specified by @Json(name="fieldName") making it difficult to override the FieldRenamer for specific fields.

The FieldRenamer is very useful when many of the JSON field names follow a different pattern to the Kotlin field names.
However when just one or two fields follow a different pattern, it would be useful to be able to use the @Json(name="fieldName") annotation to specify the exception to the rule.

The current implementation of the parsing means that the @Json annotation is processed first, then the result of that is passed to the FieldRenamer, resulting in the name provided in the annotation also being renamed.

It seems like it would be more flexible if the @Json annotation overrode the FieldRenamer.
I.e. if a @Json(name="fieldName") is present on a field, then the FieldRenamer would be skipped. The FieldRenamer would only rename fields with no name explicitly provided by an annotation.

Example

For example the following JSON could have many underscore_case fields, and just one or two fields following a different pattern.

{
    "first_name": "John",
    "last_name": "Smith",
    // ... Many more underscore_case fields ...
    "birthDate": "2024-01-01"
}

Ideally it would be possible to parse the above JSON with the following data class.
The one differently named field has the @Json("birthDate") annotation to override/skip automatic field renaming.

class Person(
    val firstName: String,
    val lastName: String,
    // ... Many more fields ...
    @Json("birthDate")
    var birthDate: String
)

Klaxon would have a FieldRenamer that renames camelCase to underscore_case to parse the majority of fields.

val renamer = object: FieldRenamer {
    override fun toJson(fieldName: String) = FieldRenamer.camelToUnderscores(fieldName)
    override fun fromJson(fieldName: String) = FieldRenamer.underscoreToCamel(fieldName)
}
val klaxon = Klaxon().fieldRenamer(renamer)
val person = klaxon.parse<Person>(json)

This currently does not behave as desired and results in an error parsing the JSON
com.beust.klaxon.KlaxonException: Unable to instantiate Person:No argument provided for a required parameter: parameter #2 birthDate of fun <init>(kotlin.String, kotlin.String, kotlin.String): Person

Proposed code change

Proposed retrieveJsonFieldName implementation which uses the @Json(name="fieldName") if present, otherwise renames the field property name.

fun retrieveJsonFieldName(klaxon: Klaxon, kc: KClass<*>, prop: KProperty1<*, *>) : String {
    val jsonAnnotation = Annotations.findJsonAnnotation(kc, prop.name)
    val fieldName =
            if (jsonAnnotation != null && jsonAnnotation.nameInitialized()) jsonAnnotation.name
            else klaxon.fieldRenamer?.toJson(prop.name) ?: prop.name
    return fieldName
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant