88import java .util .HashSet ;
99import java .util .Map ;
1010import java .util .Set ;
11- import java .util .concurrent .ConcurrentHashMap ;
1211
12+ import org .hibernate .SessionFactory ;
13+ import org .hibernate .SessionFactoryObserver ;
1314import org .hibernate .boot .internal .ClassLoaderAccessImpl ;
1415import org .hibernate .boot .registry .classloading .spi .ClassLoaderService ;
1516import org .hibernate .engine .spi .SessionFactoryImplementor ;
3132
3233import jakarta .validation .ConstraintViolation ;
3334import jakarta .validation .ConstraintViolationException ;
34- import jakarta .validation .TraversableResolver ;
3535import jakarta .validation .Validator ;
3636import jakarta .validation .ValidatorFactory ;
3737
38- import static jakarta .validation .Validation .buildDefaultValidatorFactory ;
3938import static org .hibernate .internal .util .NullnessUtil .castNonNull ;
4039import static org .hibernate .internal .util .collections .CollectionHelper .setOfSize ;
4140
4746 */
4847//FIXME review exception model
4948public class BeanValidationEventListener
50- implements PreInsertEventListener , PreUpdateEventListener , PreDeleteEventListener , PreUpsertEventListener , PreCollectionUpdateEventListener {
49+ implements PreInsertEventListener , PreUpdateEventListener , PreDeleteEventListener , PreUpsertEventListener , PreCollectionUpdateEventListener ,
50+ SessionFactoryObserver {
5151
5252 private static final CoreMessageLogger LOG = Logger .getMessageLogger (
5353 MethodHandles .lookup (),
5454 CoreMessageLogger .class ,
5555 BeanValidationEventListener .class .getName ()
5656 );
5757
58- private ValidatorFactory factory ;
59- private final ConcurrentHashMap < EntityPersister , Set < String >> associationsPerEntityPersister = new ConcurrentHashMap <>() ;
58+ private HibernateTraversableResolver traversableResolver ;
59+ private Validator validator ;
6060 private GroupsPerOperation groupsPerOperation ;
61- boolean initialized ;
62-
63- /**
64- * Constructor used in an environment where validator factory is injected (JPA2).
65- *
66- * @param factory The {@code ValidatorFactory} to use to create {@code Validator} instance(s)
67- * @param settings Configured properties
68- */
69- public BeanValidationEventListener (
70- ValidatorFactory factory , Map <String ,Object > settings , ClassLoaderService classLoaderService ) {
71- init ( factory , settings , classLoaderService );
72- }
7361
74- public void initialize (Map <String ,Object > settings , ClassLoaderService classLoaderService ) {
75- if ( !initialized ) {
76- init ( buildDefaultValidatorFactory (), settings , classLoaderService );
77- }
62+ public BeanValidationEventListener (
63+ ValidatorFactory factory , Map <String , Object > settings , ClassLoaderService classLoaderService ) {
64+ traversableResolver = new HibernateTraversableResolver ();
65+ validator = factory .usingContext ()
66+ .traversableResolver ( traversableResolver )
67+ .getValidator ();
68+ groupsPerOperation = GroupsPerOperation .from ( settings , new ClassLoaderAccessImpl ( classLoaderService ) );
7869 }
7970
80- private void init (ValidatorFactory factory , Map <String ,Object > settings , ClassLoaderService classLoaderService ) {
81- this .factory = factory ;
82- groupsPerOperation = GroupsPerOperation .from ( settings , new ClassLoaderAccessImpl ( classLoaderService ) );
83- initialized = true ;
71+ @ Override
72+ public void sessionFactoryCreated (SessionFactory factory ) {
73+ SessionFactoryImplementor implementor = factory .unwrap ( SessionFactoryImplementor .class );
74+ implementor
75+ .getMappingMetamodel ()
76+ .forEachEntityDescriptor ( entityPersister -> traversableResolver .addPersister ( entityPersister , implementor ) );
8477 }
8578
8679 public boolean onPreInsert (PreInsertEvent event ) {
@@ -143,10 +136,6 @@ private <T> void validate(
143136 if ( object == null || persister .getRepresentationStrategy ().getMode () != RepresentationMode .POJO ) {
144137 return ;
145138 }
146- TraversableResolver tr = new HibernateTraversableResolver ( persister , associationsPerEntityPersister , sessionFactory );
147- Validator validator = factory .usingContext ()
148- .traversableResolver ( tr )
149- .getValidator ();
150139 final Class <?>[] groups = groupsPerOperation .get ( operation );
151140 if ( groups .length > 0 ) {
152141 final Set <ConstraintViolation <T >> constraintViolations = validator .validate ( object , groups );
@@ -167,7 +156,7 @@ private <T> void validate(
167156 builder .append ( toString ( groups ) );
168157 builder .append ( "\n List of constraint violations:[\n " );
169158 for ( ConstraintViolation <?> violation : constraintViolations ) {
170- builder .append ( "\t " ).append ( violation .toString () ).append ("\n " );
159+ builder .append ( "\t " ).append ( violation .toString () ).append ( "\n " );
171160 }
172161 builder .append ( "]" );
173162
0 commit comments