I am using JPA with Kotlin and oppose a problem trying to encapsulate OneToMany relationships. I can easily achieve this in Java, but I have some problems related to the fact that Kotlin only has properties and fields in classes.
I have an order, and the order has one for many items. The order object has a MutableList from LineItem, but the get method SHOULD NOT return a modified list or anything that the caller could potentially change, as this interrupts the encapsulation. The order class should be responsible for managing a set of items and ensuring that all business rules / validations are followed.
This is the code that I have provided so far. I mainly use the backing property, which is a MutableList that will process the Order class, and then a transient property appears that returns Iterable, and Collections.unmodifiableList(_lineItems)ensures that even if the caller receives the list and drops it in the MutableList, t change it.
Is there a better way to ensure encapsulation and integrity. Maybe I'm just too protective of my design and approach. Ideally, no one should use getter to get and change a list, but this happens.
import java.util.*
import javax.persistence.*
@Entity
@Table(name = "order")
open class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Long? = null
@Column(name = "first_name")
lateinit var firstName: String
@Column(name = "last_name")
lateinit var lastName: String
@OneToMany(cascade = arrayOf(CascadeType.ALL), fetch = FetchType.LAZY, mappedBy = "order")
private val _lineItems: MutableList<LineItem> = ArrayList()
val lineItems: Iterable<LineItem>
@Transient get() = Collections.unmodifiableList(_lineItems)
protected constructor()
constructor(firstName: String, lastName: String) {
this.firstName = firstName
this.lastName = lastName
}
fun addLineItem(newItem: LineItem) {
this._lineItems.add(newItem)
}
}
@Entity
@Table(name = "line_item")
open class LineItem {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Long? = null
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "order_id", referencedColumnName = "id")
lateinit var order: Order
private set
protected constructor()
constructor(order: Order) {
this.order = order
}
}
source
share