diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java index 2c237529ea8..49e267f4343 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java @@ -675,7 +675,7 @@ public class DefaultPersistenceUnitManager } SpringPersistenceUnitInfo pui = this.persistenceUnitInfos.values().iterator().next(); this.persistenceUnitInfos.clear(); - return pui.toSmartPersistenceUnitInfo(); + return pui.asStandardPersistenceUnitInfo(); } @Override @@ -691,7 +691,7 @@ public class DefaultPersistenceUnitManager "Persistence unit with name '" + persistenceUnitName + "' already obtained"); } } - return pui.toSmartPersistenceUnitInfo(); + return pui.asStandardPersistenceUnitInfo(); } } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java index 20c0386eef5..35d02a65d59 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java @@ -34,6 +34,7 @@ import org.springframework.util.Assert; * Spring's mutable equivalent of the JPA * {@link jakarta.persistence.spi.PersistenceUnitInfo} interface, * used to bootstrap an {@code EntityManagerFactory} in a container. + * This is the type exposed to {@link PersistenceUnitPostProcessor}. * *
This implementation is largely a JavaBean, offering mutators * for all standard {@code PersistenceUnitInfo} properties. @@ -42,10 +43,16 @@ import org.springframework.util.Assert; * (for achieving compatibility between JPA 3.2 and 4.0 and for preventing * late mutation attempts through {@code PersistenceUnitInfo} downcasts). * + *
For custom bootstrapping purposes, use {@link SpringPersistenceUnitInfo} + * instead, turning it into a {@code jakarta.persistence.spi.PersistenceUnitInfo} + * through {@link SpringPersistenceUnitInfo#asStandardPersistenceUnitInfo()}. + * * @author Rod Johnson * @author Juergen Hoeller * @author Costin Leau * @since 2.0 + * @see PersistenceUnitPostProcessor#postProcessPersistenceUnitInfo + * @see SpringPersistenceUnitInfo#asStandardPersistenceUnitInfo() */ public class MutablePersistenceUnitInfo { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java index af7f587ae86..4b2c9f9703a 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java @@ -22,6 +22,7 @@ import java.lang.reflect.Proxy; import jakarta.persistence.PersistenceUnitTransactionType; import jakarta.persistence.spi.ClassTransformer; +import jakarta.persistence.spi.PersistenceUnitInfo; import org.apache.commons.logging.LogFactory; import org.jspecify.annotations.Nullable; @@ -35,26 +36,56 @@ import org.springframework.util.ReflectionUtils; * Subclass of {@link MutablePersistenceUnitInfo} that adds instrumentation hooks based on * Spring's {@link org.springframework.instrument.classloading.LoadTimeWeaver} abstraction. * - *
This class is restricted to package visibility, in contrast to its superclass. + *
As of 7.0, this class is public for custom bootstrapping purposes. A fully configured + * {@code SpringPersistenceUnitInfo} instance can be turned into a standard JPA descriptor + * through {@link #asStandardPersistenceUnitInfo} (returning a JPA 3.2/4.0 adapted proxy). + * + *
Note: For post-processing within a {@code LocalContainerEntityManagerFactoryBean} + * bootstrap, the base type {@code MutablePersistenceUnitInfo} is entirely sufficient. * * @author Rod Johnson * @author Juergen Hoeller * @author Costin Leau - * @since 2.0 - * @see PersistenceUnitManager + * @since 7.0 + * @see DefaultPersistenceUnitManager */ -class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { +public class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { private @Nullable LoadTimeWeaver loadTimeWeaver; private @Nullable ClassLoader classLoader; + /** + * Construct a new SpringPersistenceUnitInfo for custom purposes. + * @param loadTimeWeaver the LoadTimeWeaver to use + */ + public SpringPersistenceUnitInfo(LoadTimeWeaver loadTimeWeaver) { + init(loadTimeWeaver); + } + + /** + * Construct a new SpringPersistenceUnitInfo for custom purposes. + * @param classLoader the ClassLoader to use + */ + public SpringPersistenceUnitInfo(ClassLoader classLoader) { + init(classLoader); + } + + /** + * Construct a SpringPersistenceUnitInfo for internal purposes. + * @see #init(LoadTimeWeaver) + * @see #init(ClassLoader) + */ + SpringPersistenceUnitInfo() { + } + + /** * Initialize this PersistenceUnitInfo with the LoadTimeWeaver SPI interface * used by Spring to add instrumentation to the current class loader. */ - public void init(LoadTimeWeaver loadTimeWeaver) { + void init(LoadTimeWeaver loadTimeWeaver) { Assert.notNull(loadTimeWeaver, "LoadTimeWeaver must not be null"); this.loadTimeWeaver = loadTimeWeaver; this.classLoader = loadTimeWeaver.getInstrumentableClassLoader(); @@ -64,11 +95,10 @@ class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { * Initialize this PersistenceUnitInfo with the current class loader * (instead of with a LoadTimeWeaver). */ - public void init(@Nullable ClassLoader classLoader) { + void init(@Nullable ClassLoader classLoader) { this.classLoader = classLoader; } - /** * This implementation returns the LoadTimeWeaver's instrumentable ClassLoader, * if specified. @@ -102,20 +132,26 @@ class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { return tcl; } - /** - * Expose a {@link SmartPersistenceUnitInfo} proxy for the persistence unit - * configuration in this {@link MutablePersistenceUnitInfo} instance. - * @since 7.0 + * Expose a standard {@code jakarta.persistence.spi.PersistenceUnitInfo} proxy for the + * persistence unit configuration in this {@code SpringPersistenceUnitInfo} instance. + *
The returned proxy implements {@code jakarta.persistence.spi.PersistenceUnitInfo} + * (and its extended variant {@link SmartPersistenceUnitInfo}) for use with persistence + * provider bootstrapping. Note that the returned proxy is effectively unmodifiable and + * cannot be downcast to {@code Mutable/SpringPersistenceUnitInfo}. */ - public SmartPersistenceUnitInfo toSmartPersistenceUnitInfo() { - return (SmartPersistenceUnitInfo) Proxy.newProxyInstance(getClass().getClassLoader(), + public PersistenceUnitInfo asStandardPersistenceUnitInfo() { + return (PersistenceUnitInfo) Proxy.newProxyInstance(getClass().getClassLoader(), new Class>[] {SmartPersistenceUnitInfo.class}, - new JpaPersistenceUnitInfoInvocationHandler()); + new SmartPersistenceUnitInfoInvocationHandler()); } - private class JpaPersistenceUnitInfoInvocationHandler implements InvocationHandler { + /** + * Invocation handler for a JPA-compliant {@link SmartPersistenceUnitInfo} proxy, + * delegating to the corresponding methods on {@link SpringPersistenceUnitInfo}. + */ + private class SmartPersistenceUnitInfoInvocationHandler implements InvocationHandler { @SuppressWarnings("unchecked") @Override @@ -127,7 +163,6 @@ class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { // Regular methods to be delegated to SpringPersistenceUnitInfo Method targetMethod = SpringPersistenceUnitInfo.class.getMethod(method.getName(), method.getParameterTypes()); - ReflectionUtils.makeAccessible(targetMethod); Object returnValue = ReflectionUtils.invokeMethod(targetMethod, SpringPersistenceUnitInfo.this, args); // Special handling for JPA 3.2 vs 4.0 getTransactionType() return type