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

Instantiate Kotlin data classes using the _primary_ constructor #2933

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jawo-a
Copy link

@jawo-a jawo-a commented Jul 11, 2022

A lot of Kotlin projects define DTOs using data classes with optional parameters like

data class Person(
    val name: String? = null,
    val email: String? = null
)

Unfortunately these data classes do not work with MapStruct because the Kotlin compiler generates multiple constructors under the hood.
Issues #2281, #2378 describe this problem.

This PR is an attempt to make MapStruct use the primary constructor of the data class to instantiate it, and ignore all other generated constructors.

How it works?

Recognizes data classes and the primary constructor by

Note: There might be false positives.

How to review?

TODO

  • Update the reference documentation

Improvement ideas

  • Instead of using the number of componentN() methods, use their exact return types to more accurately determine the primary constructor.

Recognizes data classes and the primary constructor by the presence of the annotation `kotlin.Metadata` and `componentN()` methods, although there might be false positives.
@sskrla
Copy link

sskrla commented Jul 12, 2022

You could also maybe use the generated copy method as a form of detection?

@jawo-a
Copy link
Author

jawo-a commented Jul 13, 2022

@sskrla Yes, I've taken a look at decompiled data classes and the generated copy() method has exactly the same parameters as the primary constructor, although I'm not sure if that is actually guaranteed by Kotlin.

@filiphr
Copy link
Member

filiphr commented Jul 24, 2022

This is an interesting approach @jawo-a. However, I am not sure that I like the taken approach with using the component method count. I would prefer in using the kotlinx-metadata-jvm library as an optional dependency instead. Perhaps with a mapstruct-kotlin-extensions or some other extension that will pull the needed Kotlin dependencies and that will have the needed code to make Kotlin things work properly.

@DavidRomao
Copy link

Hi @filiphr , how would you suggest that mapstruct-kotlin-extensions extension be done ? Would it be okay through the creation of a Constructor Provider SPI, where that extenstion package would then implement ? Otherwise mapstruct would load the current implementation

@jawo-a
Copy link
Author

jawo-a commented Dec 13, 2022

@DavidRomao I've already prepared a change with a Constructor Provider SPI. Going to open a PR in the next few weeks.

@MiguelAngelLV
Copy link

Any change with this?

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

Successfully merging this pull request may close these issues.

None yet

5 participants