diff --git a/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/ReadOnlyAssociationsPersistentHooks.kt b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/ReadOnlyAssociationsPersistentHooks.kt new file mode 100644 index 0000000..92de200 --- /dev/null +++ b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/ReadOnlyAssociationsPersistentHooks.kt @@ -0,0 +1,54 @@ +package dev.krud.crudframework.jpa.association + +import dev.krud.crudframework.crud.hooks.interfaces.UpdateFromHooks +import dev.krud.crudframework.crud.hooks.interfaces.UpdateHooks +import dev.krud.crudframework.model.BaseCrudEntity +import dev.krud.crudframework.util.ReflectionUtils +import jakarta.persistence.CascadeType +import jakarta.persistence.EntityManager +import jakarta.persistence.ManyToMany +import jakarta.persistence.ManyToOne +import jakarta.persistence.OneToMany +import jakarta.persistence.OneToOne +import jakarta.persistence.PersistenceContext +import org.hibernate.Hibernate +import org.hibernate.Session + +class ReadOnlyAssociationsPersistentHooks : + UpdateHooks>, + UpdateFromHooks> { + + @PersistenceContext + private lateinit var entityManager: EntityManager + + override fun onUpdate(entity: BaseCrudEntity) { + markAssociationsReadOnly(entity) + } + + override fun onUpdateFrom(entity: BaseCrudEntity, ro: Any) { + markAssociationsReadOnly(entity) + } + + private fun markAssociationsReadOnly(entity: BaseCrudEntity) { + val session = entityManager.unwrap(Session::class.java) + ReflectionUtils.doWithFields(entity::class.java) { field -> + val cascade = when { + field.isAnnotationPresent(ManyToOne::class.java) -> field.getAnnotation(ManyToOne::class.java).cascade + field.isAnnotationPresent(OneToOne::class.java) -> field.getAnnotation(OneToOne::class.java).cascade + field.isAnnotationPresent(ManyToMany::class.java) -> field.getAnnotation(ManyToMany::class.java).cascade + field.isAnnotationPresent(OneToMany::class.java) -> field.getAnnotation(OneToMany::class.java).cascade + else -> return@doWithFields + } + if (CascadeType.ALL in cascade || CascadeType.MERGE in cascade) return@doWithFields + ReflectionUtils.makeAccessible(field) + val value = field.get(entity) ?: return@doWithFields + if (value is Collection<*>) { + if (Hibernate.isInitialized(value)) { + value.filterNotNull().forEach { session.setReadOnly(it, true) } + } + } else { + session.setReadOnly(value, true) + } + } + } +} diff --git a/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/annotation/ReadOnlyAssociations.kt b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/annotation/ReadOnlyAssociations.kt new file mode 100644 index 0000000..ad7bf7f --- /dev/null +++ b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/association/annotation/ReadOnlyAssociations.kt @@ -0,0 +1,7 @@ +package dev.krud.crudframework.jpa.association.annotation + +import dev.krud.crudframework.crud.annotation.WithHooks +import dev.krud.crudframework.jpa.association.ReadOnlyAssociationsPersistentHooks + +@WithHooks(hooks = [ReadOnlyAssociationsPersistentHooks::class]) +annotation class ReadOnlyAssociations diff --git a/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/config/CrudHibernate5ConnectorConfiguration.kt b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/config/CrudHibernate5ConnectorConfiguration.kt index d5554e7..78a90d8 100644 --- a/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/config/CrudHibernate5ConnectorConfiguration.kt +++ b/crud-framework-hibernate5-connector/src/main/java/dev/krud/crudframework/jpa/config/CrudHibernate5ConnectorConfiguration.kt @@ -1,6 +1,7 @@ package dev.krud.crudframework.jpa.config import dev.krud.crudframework.crud.handler.CrudDao +import dev.krud.crudframework.jpa.association.ReadOnlyAssociationsPersistentHooks import dev.krud.crudframework.jpa.dao.JpaDaoImpl import dev.krud.crudframework.jpa.lazyinitializer.LazyInitializerPersistentHooks import org.springframework.context.annotation.Bean @@ -13,4 +14,7 @@ class CrudHibernate5ConnectorConfiguration { @Bean fun lazyInitializerPersistentHooks(): LazyInitializerPersistentHooks = LazyInitializerPersistentHooks() + + @Bean + fun readOnlyAssociationsPersistentHooks(): ReadOnlyAssociationsPersistentHooks = ReadOnlyAssociationsPersistentHooks() } \ No newline at end of file