From 39dfe29c93cf6cb67fbc8bd9bf6410b7d024bc7d Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Fri, 17 Oct 2025 17:17:48 +0200 Subject: [PATCH] HHH-19884 Custom `@ClassTemplate` lifecycle annotations and extension --- .../testing/orm/junit/AfterClassTemplate.java | 22 ++++++++++ .../orm/junit/BeforeClassTemplate.java | 22 ++++++++++ ...sTemplateInvocationListenersExtension.java | 44 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/AfterClassTemplate.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/BeforeClassTemplate.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ClassTemplateInvocationListenersExtension.java diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/AfterClassTemplate.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/AfterClassTemplate.java new file mode 100644 index 000000000000..09fa3e27633e --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/AfterClassTemplate.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.testing.orm.junit; + +import org.hibernate.Incubating; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Similar to JUnit's {@link org.junit.jupiter.api.AfterAll} but called after + * each template invocation in a {@link @ClassTemplate} test class. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Incubating +public @interface AfterClassTemplate { +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/BeforeClassTemplate.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/BeforeClassTemplate.java new file mode 100644 index 000000000000..a6d0089bfafd --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/BeforeClassTemplate.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.testing.orm.junit; + +import org.hibernate.Incubating; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Similar to JUnit's {@link org.junit.jupiter.api.BeforeAll} but called before + * each template invocation in a {@link @ClassTemplate} test class. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Incubating +public @interface BeforeClassTemplate { +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ClassTemplateInvocationListenersExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ClassTemplateInvocationListenersExtension.java new file mode 100644 index 000000000000..883536064d35 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ClassTemplateInvocationListenersExtension.java @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.testing.orm.junit; + +import org.hibernate.Incubating; +import org.junit.jupiter.api.extension.AfterClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.BeforeClassTemplateInvocationCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +import static org.junit.platform.commons.support.AnnotationSupport.findAnnotatedMethods; +import static org.junit.platform.commons.support.HierarchyTraversalMode.BOTTOM_UP; + +/** + * JUnit extension to provide hooks for methods annotated with {@link BeforeClassTemplate} + * and {@link AfterClassTemplate} to be called before and after each class template invocation + *

+ * Provides native support for methods with zero parameters or a single parameter typed either + * as {@link EntityManagerFactoryScope} or {@link SessionFactoryScope}, for easy integration + * with the {@link EntityManagerFactoryExtension entity manager} and {@link SessionFactoryExtension + * session factory} extensions. + */ +@Incubating +public class ClassTemplateInvocationListenersExtension + implements BeforeClassTemplateInvocationCallback, AfterClassTemplateInvocationCallback { + @Override + public void beforeClassTemplateInvocation(ExtensionContext context) throws Exception { + final var testClass = context.getRequiredTestClass(); + final var annotatedMethods = findAnnotatedMethods( testClass, BeforeClassTemplate.class, BOTTOM_UP ); + for ( final var method : annotatedMethods ) { + context.getExecutableInvoker().invoke( method, context.getRequiredTestInstance() ); + } + } + + @Override + public void afterClassTemplateInvocation(ExtensionContext context) throws Exception { + final var testClass = context.getRequiredTestClass(); + final var annotatedMethods = findAnnotatedMethods( testClass, AfterClassTemplate.class, BOTTOM_UP ); + for ( final var method : annotatedMethods ) { + context.getExecutableInvoker().invoke( method, context.getRequiredTestInstance() ); + } + } +}