Skip to content

Support Kotlin value class properties in SpEL #30468

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

Closed
christianhujer opened this issue May 10, 2023 · 3 comments
Closed

Support Kotlin value class properties in SpEL #30468

christianhujer opened this issue May 10, 2023 · 3 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: kotlin An issue related to Kotlin support type: enhancement A general enhancement
Milestone

Comments

@christianhujer
Copy link

christianhujer commented May 10, 2023

It would be great if SpringEL could be improved to support Kotlin Value Classes (probably by unmangling mangled Kotlin names).

I had the following issue.

Class:

data class Something(
    val id: UUID<Something>,
    val name: String,
)

It worked everywhere except in Thymeleaf. When I was using it in Thymeleaf, I got an exception:

org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/pages/Something.html]")
Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "something.id" (template: "pages/Something" - line 277, col 4)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "something.id" (template: "pages/Something" - line 277, col 4)
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'id' cannot be found on object of type 'com.example.Something' - maybe not public or not valid?

Turns out, the problem was that the field id was of a type that itself is a Kotlin Value Class.

What are Kotlin Value Classes?

Kotlin Value Classes are classes that wrap other values, granting more type safety during compilation in Kotlin, without introducing the indirection overhead of a regular class.

Examples:

@JvmInline value class Latitude(val latitude: Double)
@JvmInline value class Longitude(val longitude: Double)
@JvmInline value class UUID<TargetType>(val value: java.util.UUID)

When value classes are used, the Kotlin compiler mangles the name of the context function to prevent name conflicts when overloading:

class Location {
    fun updateLocation(latitude: Double, longitude: Double)
    fun updateLocation(latitude: Latitude, longitude: Longitude)
}

The actual signature of the second updateLocation function would also be updateLocation(Double, Double), which clashes with the first definition. To prevent that, Kotlin mangles the name into something like updateLocation-hash.

This also applies to the getter for properties:

data class Location(
    val latitude: Latitude,
    val longitude: Longitude,
)

@Entity data class Something(
    @Id
    val id: UUID<Something>,
    val name: String,
)

The names for the getters of the properties will be mangled.

To work nicely in Spring, a few pieces are required:

  • Support by Jackson Serialization - done, Jackson detects and unmangles mangled names to get JSON property names without the mangling suffix. 👍
  • Support by Jackson Deserialization - open
  • Support by Hibernate - done, Hibernate detects and unmangles mangled names to create column names without the mangling suffix. 👍
  • Support by SpringEL - missing, SpringEL is unaware of Kotlin's name mangling. This is of particular interest for Thymeleaf users as Spring Thymeleaf uses SpringEL inside HTML.

Workaround: Until SpringEL supports Kotlin name mangling, explicitly override the mangled getter name, like this:

data class Location(
    @get:JvmName("getLatitude")
    val latitude: Latitude,
    @get:JvmName("getLongitude")
    val longitude: Longitude,
)

@Entity data class Something(
    @Id
    @get:JvmName("id")
    val id: UUID<Something>,
    val name: String,
)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 10, 2023
@quaff
Copy link
Contributor

quaff commented May 11, 2023

Support by Jackson - done, Jackson detects and unmangles mangled names to get JSON property names without the mangling suffix. 👍

Jackson only supports serialization of value class, deserialization is not supported yet.
FasterXML/jackson-module-kotlin#650

@christianhujer
Copy link
Author

Might be related to this one? #28638

@christianhujer
Copy link
Author

Support by Jackson - done, Jackson detects and unmangles mangled names to get JSON property names without the mangling suffix. +1

Jackson only supports serialization of value class, deserialization is not supported yet. FasterXML/jackson-module-kotlin#650

Ah thanks for clarifying. I've updated my comment accordingly. Seems I got lucky so far that I didn't have Deserialization issues on value classes.

@sdeleuze sdeleuze added the theme: kotlin An issue related to Kotlin support label May 11, 2023
@sdeleuze sdeleuze self-assigned this Aug 10, 2023
@sdeleuze sdeleuze changed the title Feature Request: Support Kotlin Value Classes in SpringEL (Spring Expression Language) Support Kotlin value classes in SpEL Aug 10, 2023
@sdeleuze sdeleuze added in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Aug 10, 2023
@sdeleuze sdeleuze added this to the 6.1.0-M4 milestone Aug 10, 2023
@sdeleuze sdeleuze changed the title Support Kotlin value classes in SpEL Support Kotlin value classes property or field in SpEL Aug 10, 2023
@sdeleuze sdeleuze changed the title Support Kotlin value classes property or field in SpEL Support Kotlin value classes property in SpEL Aug 11, 2023
@sdeleuze sdeleuze changed the title Support Kotlin value classes property in SpEL Support Kotlin value class properties in SpEL Aug 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: kotlin An issue related to Kotlin support type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants