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

Unable to use secondary @PersistenceConstructor with Kotlin data classes [DATACMNS-1338] #1775

Closed
spring-projects-issues opened this issue Jun 10, 2018 · 3 comments

Comments

@spring-projects-issues
Copy link

@spring-projects-issues spring-projects-issues commented Jun 10, 2018

Daniel Jones opened DATACMNS-1338 and commented

I'm using Kotlin Data Classes for my entities. This means all properties must be defined in the primary constructor, including properties annotated with @DBRef. This means that by default, even if properties are annotated with @DBRef(lazy = true), they're still eagerly loaded because KotlinClassGeneratingEntityInstantiator.DefaultingKotlinClassInstantiatorAdapter will load the field when trying to instantiate the class.

I've worked around this like so:

@Document(collection = "users")
@TypeAlias("user")
data class CustomUser(
        @Id var id: String? = null,

        @DBRef(lazy = true)
        var organisations: MutableList<Organisation> = mutableListOf()
) {
    @PersistenceConstructor
    constructor(id: String?): this(id, mutableListOf())
}

However I now get the error:

Failed to instantiate my.package.CustomUser using constructor fun <init>(kotlin.String?): my.package.CustomUser with arguments user123,0,null 

With the causing exception:

Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.List 

This is because the parameter array is constructed based off the metadata from the @PersistenceConstructor ("0,null" are the default bitmask and the DefaultConstructorMarker) but the ObjectInstantiator is built using the default constructor as per KotlinClassGeneratingEntityInstantiator#doCreateEntityInstantiator


Affects: 2.0.7 (Kay SR7), 2.1 M3 (Lovelace)

Issue Links:

  • DATAMONGO-2004 Lazily resolve DBRefs during constructor creation of the enclosing entity

Referenced from: commits 3ea24a1, 53560e0

Backported to: 2.0.8 (Kay SR8)

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Jun 10, 2018

Mark Paluch commented

Good catch. The issue originates in an imprecise comparison of constructor arguments. We did not calculate the exact count of defaulting masks and the constructor's first argument type matches with the one from the primary synthetic constructor.

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Jun 10, 2018

Mark Paluch commented

That's fixed now, snapshot build artifacts are in place. Care to give spring-data-commons-2.0.8.BUILD-SNAPSHOT a try?

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Jun 10, 2018

Daniel Jones commented

Awesome! Nice work, works like a charm.

Although turns out I still can't use data classes for this use-case because @DBRef(lazy = true) creates a proxy 😭

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants