From 2f397610bd2c21bab1d77aaee4bc1a0a23ee1245 Mon Sep 17 00:00:00 2001 From: "Jonathan S. Fisher" Date: Tue, 28 Nov 2023 17:20:23 -0600 Subject: [PATCH] Close #1806 - Have to the ability to dynamically set the Validation Group during a transaction --- .../config/EntityManagerProperties.java | 18 +++++++ .../listeners/BeanValidationListener.java | 48 +++++++++++++++---- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/EntityManagerProperties.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/EntityManagerProperties.java index b13537c346c..d485e29cf66 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/EntityManagerProperties.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/EntityManagerProperties.java @@ -319,6 +319,21 @@ public class EntityManagerProperties { * ) */ public static final String COMPOSITE_UNIT_PROPERTIES = PersistenceUnitProperties.COMPOSITE_UNIT_PROPERTIES; + + /** + * Overrides the Bean Validation Group(s) that will execute during a prePersist event. This should be a class or class[]. + */ + public static final String VALIDATION_GROUP_PRE_PERSIST = "eclipselink.validation.group.prePersist"; + + /** + * Overrides the Bean Validation Group(s) that will execute during a preUpdate event. This should be a class or class[]. + */ + public static final String VALIDATION_GROUP_PRE_UPDATE = "eclipselink.validation.group.preUpdate"; + + /** + * Overrides the Bean Validation Group(s) that will execute during a preRemove event. This should be a class or class[]. + */ + public static final String VALIDATION_GROUP_PRE_REMOVE = "eclipselink.validation.group.preRemove"; private static final Set supportedProperties = new HashSet() { @@ -344,6 +359,9 @@ public class EntityManagerProperties { add(PERSISTENCE_CONTEXT_COMMIT_ORDER); add(FLUSH_CLEAR_CACHE); add(COMPOSITE_UNIT_PROPERTIES); + add(VALIDATION_GROUP_PRE_PERSIST); + add(VALIDATION_GROUP_PRE_UPDATE); + add(VALIDATION_GROUP_PRE_REMOVE); } }; diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/listeners/BeanValidationListener.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/listeners/BeanValidationListener.java index f92b68239f3..b52d7d97005 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/listeners/BeanValidationListener.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/listeners/BeanValidationListener.java @@ -36,17 +36,20 @@ import javax.validation.ValidatorFactory; import javax.validation.groups.Default; +import org.eclipse.persistence.config.EntityManagerProperties; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; import org.eclipse.persistence.descriptors.FetchGroupManager; +import org.eclipse.persistence.exceptions.BeanValidationException; import org.eclipse.persistence.internal.localization.ExceptionLocalization; import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.mappings.ForeignReferenceMapping; + /** * Responsible for performing automatic bean validation on call back events. * @author Mitesh Meswani @@ -72,7 +75,7 @@ public BeanValidationListener(ValidatorFactory validatorFactory, Class[] groupPr @Override public void prePersist (DescriptorEvent event) { - // since we are using prePersist to perform validation, invlid data may get inserted into database as shown by + // since we are using prePersist to perform validation, invalid data may get inserted into database as shown by // following example // tx.begin() // e = new MyEntity(...); @@ -81,19 +84,38 @@ public void prePersist (DescriptorEvent event) { // tx.commit(); // "invalid data" would get inserted into database. // - // preInsert can be used to work around above issue. Howerver, the JPA spec does not itent it. + // preInsert can be used to work around above issue. However, the JPA spec does not itent it. // This might be corrected in next iteration of spec - validateOnCallbackEvent(event, "prePersist", groupPrePersit); + Object overrideGroups = event.getSession().getParent().getProperties().get(EntityManagerProperties.VALIDATION_GROUP_PRE_PERSIST); + if (overrideGroups != null) { + if (overrideGroups instanceof Class) { + overrideGroups = new Class[] { (Class) overrideGroups }; + } else if (!(overrideGroups instanceof Class[])) { + throw new BeanValidationException("prePersist validation group must be a Class or Class Array:" + overrideGroups); + } + validateOnCallbackEvent(event, "prePersist", (Class[]) overrideGroups); + } else { + validateOnCallbackEvent(event, "prePersist", groupPrePersit); + } } - @Override public void aboutToUpdate(DescriptorEvent event) { Object source = event.getSource(); UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl )event.getSession(); // preUpdate is also generated for deleted objects that were modified in this UOW. // Do not perform preUpdate validation for such objects as preRemove would have already been called. - if(!unitOfWork.isObjectDeleted(source)) { - validateOnCallbackEvent(event, "preUpdate", groupPreUpdate); + if (!unitOfWork.isObjectDeleted(source)) { + Object overrideGroups = event.getSession().getParent().getProperties().get(EntityManagerProperties.VALIDATION_GROUP_PRE_UPDATE); + if (overrideGroups != null) { + if (overrideGroups instanceof Class) { + overrideGroups = new Class[] { (Class) overrideGroups }; + } else if (!(overrideGroups instanceof Class[])) { + throw new BeanValidationException("preUpdate validation group must be a Class or Class Array:" + overrideGroups); + } + validateOnCallbackEvent(event, "preUpdate", (Class[]) overrideGroups); + } else { + validateOnCallbackEvent(event, "preUpdate", groupPreUpdate); + } } } @@ -104,9 +126,17 @@ public void preUpdateWithChanges(DescriptorEvent event) { @Override public void preRemove (DescriptorEvent event) { - if(groupPreRemove != null) { //No validation performed on preRemove if user has not explicitly specified a validation group - validateOnCallbackEvent(event, "preRemove", groupPreRemove); - } + Object overrideGroups = event.getSession().getParent().getProperties().get(EntityManagerProperties.VALIDATION_GROUP_PRE_REMOVE); + if (overrideGroups != null) { + if (overrideGroups instanceof Class) { + overrideGroups = new Class[] { (Class) overrideGroups }; + } else if (!(overrideGroups instanceof Class[])) { + throw new BeanValidationException("preRemove validation group must be a Class or Class Array:" + overrideGroups); + } + validateOnCallbackEvent(event, "preRemove", (Class[]) overrideGroups); + } else if (groupPreRemove != null) { // No validation performed on preRemove if user has not explicitly specified a validation group + validateOnCallbackEvent(event, "preRemove", groupPreRemove); + } } private void validateOnCallbackEvent(DescriptorEvent event, String callbackEventName, Class[] validationGroup) {