Search code examples
postgresqlkotlinmicronautdata-class

Converting a data class to a @MappedEntity data class in Micronaut using Kotlin


Firstly, I'm new to micronaut and kotlin.

I'm trying to convert a data class that I receive as a request body to my API. I need to persist data from this json into a Postgres table. I wasn't able to add @field annotation to a @MappedEntity data class to validate empty fields with a message. Hence, I decided to use a normal data class to parse the request body and then create a new object of the @MappedEntity class to run the save query.

The issue:

I have a @GeneratedValue Id column in my mapped Entity class. When I try to create a new object of this class, I'm not able to leave the Id column blank.

Controller:

@Post("/contribute")
    @Status(HttpStatus.CREATED)
    fun processIndividualContribution(
        @Valid @Body individualContributionRequestTO: IndividualContributionRequestTO
    ): Mono<IndividualContributionDTO>

Request Body Data CLass:

@JsonIgnoreProperties(ignoreUnknown = true)
data class IndividualContributionRequestTO(
    @field: NotEmpty(message = "Transaction Id cannot be null") val transactionId: String,
    @field: NotEmpty(message = "First Name can't be null") val firstName: String,
    val lastName: String? = null,
    @field: NotEmpty(message = "Email address can't be null") val emailAddress: String,
    @field: NotEmpty(message = "Individual Contribution can't be null") val contribution: String,
)
    {
    fun toPurchasedDataEntity(individualContributionRequestTO: IndividualContributionRequestTO): PurchaseDataAll{
        return PurchaseDataAll(
            purchaserFirstName = individualContributionRequestTO.firstName,
            purchaserLastName = individualContributionRequestTO.lastName,
            purchaserEmail = individualContributionRequestTO.emailAddress,
            contribution = individualContributionRequestTO.contribution
        )
    }
}

Mapped Entity Class:

@MappedEntity
@Table(name="purchased_all")
data class PurchaseDataAll (

    @Id
    @GeneratedValue
    @Column(name = "purchase_id")
    val purchaseId: Int,

    @Column(name = "transaction_id")
    val transactionId: String,

    @Column(name = "purchaser_first_name")
    val purchaserFirstName: String,

    @Column(name = "purchaser_last_name")
    val purchaserLastName: String? = null,

    @Column(name = "purchaser_email")
    val purchaserEmail: String,

    @Column(name = "contribution")
    val contribution: String,

    @DateCreated
    @Column(name = "created_ts")
    var createdTs: LocalDateTime? = null,

    @DateUpdated
    @Column(name = "updated_ts")
    var updatedTs: LocalDateTime? = null

)

The function toPurchasedDataEntity doesn't compile due to the missing purchaseId field in the returned object.

Is there a way I can parse the request body data class to the mapped entity class by ignoring the auto generated field?


Solution

  • In Kotlin, you'll have to prefix annotations witn field: like shown below. I also changed def for purchaseId so you don't have to specify it when mapping from view class (DTO) to entity class.

    IMHO, I think it's a good approach to separate entity classes from view classes as you've done in your question.

    @MappedEntity
    @Table(name="purchased_all")
    data class PurchaseDataAll (
    
        @field:Id
        @field:GeneratedValue
        @field:Column(name = "purchase_id")
        var purchaseId: Int? = null,
    
        @field:Column(name = "transaction_id")
        val transactionId: String,
    
        @field:Column(name = "purchaser_first_name")
        val purchaserFirstName: String,
    
        @field:Column(name = "purchaser_last_name")
        val purchaserLastName: String? = null,
    
        @field:Column(name = "purchaser_email")
        val purchaserEmail: String,
    
        @field:Column(name = "contribution")
        val contribution: String,
    
        @field:DateCreated
        @field:Column(name = "created_ts")
        var createdTs: LocalDateTime? = null,
    
        @field:DateUpdated
        @field:Column(name = "updated_ts")
        var updatedTs: LocalDateTime? = null
    )