Open
Description
Related to this question on Stack Overflow.
Entity Example:
@Id
@GeneratedValue(generator = "SharedPrimaryKeyGenerator")
@GenericGenerator(
name = "SharedPrimaryKeyGenerator",
strategy = "foreign",
parameters = [Parameter(name = "property", value = "bookLineItem")]
)
@Column(
name = ENTITY_B_ID,
unique = true,
nullable = false
)
var entityBId: Int? = null
@OneToOne
@PrimaryKeyJoinColumn
@JsonBackReference
var entityA: EntityA? = null
Custom generator:
class ReactiveSharedPrimaryKeyGenerator: ReactiveIdentifierGenerator<Int> {
override fun generate(p0: ReactiveConnectionSupplier?, entity: Any?): CompletionStage<Int> {
return CompletableFuture.supplyAsync {
val primaryKey = getPrimaryKey(entity!!)
primaryKey as Int ?: throw IllegalStateException("Primary Key value is null")
}.toCompletableFuture()
}
/**
* Returns the ID or the One2One parent by checking for the @PrimaryKeyJoinColumn field to retrieve the parent
* and then searches for the field annotated with @Id to retrieve the ID of the parent
*/
fun getPrimaryKey(entity: Any?): Int? {
entity?.let {
var currentClass: Class<*> = it::class.java
while (currentClass != null && currentClass != Any::class.java) {
currentClass.declaredFields.forEach { field ->
val annotation = field.getAnnotation(PrimaryKeyJoinColumn::class.java)
annotation?.let { an ->
field.trySetAccessible()
val primaryKeyOwner = field.get(it)
primaryKeyOwner?.let { pk ->
val primaryKeyField = pk::class.java.getDeclaredFields().find { pkF ->
pkF.getAnnotation(javax.persistence.Id::class.java) != null
}
if (primaryKeyField != null) {
primaryKeyField.trySetAccessible()
val pkId = primaryKeyField.get(pk)
return pkId as Int?
}
}
}
}
currentClass = currentClass.superclass
}
}
return null
}
}
If somebody wants to provide a test, we a similar use case in OneToOneMapsIdTest, except that it doesn't use a custom generator.