Jakarta Persistence API provides a comprehensive framework for object-relational mapping, entity lifecycle management, and database operations in Java applications
Complete reference for entity lifecycle management, persistence context operations, and transaction handling in Jakarta Persistence.
import jakarta.persistence.*;Create EntityManagerFactory instances to manage entity managers.
/**
* Bootstrap class for obtaining EntityManagerFactory instances
* @since 1.0
*/
public class Persistence {
/**
* Create and return an EntityManagerFactory for the named persistence unit
* @param persistenceUnitName the name of the persistence unit
* @return the factory for the persistence unit
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName);
/**
* Create and return an EntityManagerFactory with properties
* @param persistenceUnitName the name of the persistence unit
* @param properties additional properties to use when creating the factory
* @return the factory for the persistence unit
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties);
/**
* Generate database schemas and/or tables
* @param persistenceUnitName the name of the persistence unit
* @param map properties for schema generation
*/
public static void generateSchema(String persistenceUnitName, Map map);
/**
* Return the PersistenceUtil instance
* @return PersistenceUtil instance
*/
public static PersistenceUtil getPersistenceUtil();
}
/**
* Utility interface for working with entities
* @since 2.0
*/
public interface PersistenceUtil {
/**
* Determine the load state of an entity attribute
* @param entity the entity instance
* @param attributeName name of the attribute
* @return true if the attribute is loaded
*/
boolean isLoaded(Object entity, String attributeName);
/**
* Determine the load state of an entity
* @param entity the entity instance
* @return true if all EAGER attributes are loaded
*/
boolean isLoaded(Object entity);
}Usage Example:
// Create EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit");
// With properties
Map<String, Object> props = new HashMap<>();
props.put("jakarta.persistence.jdbc.url", "jdbc:postgresql://localhost/mydb");
props.put("jakarta.persistence.jdbc.user", "user");
props.put("jakarta.persistence.jdbc.password", "password");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU", props);
// Check if entity is loaded
PersistenceUtil util = Persistence.getPersistenceUtil();
boolean isLoaded = util.isLoaded(entity, "orders");Factory for creating EntityManager instances.
/**
* Interface for entity manager factory
* @since 1.0
*/
public interface EntityManagerFactory extends AutoCloseable {
/**
* Create a new application-managed EntityManager
* @return entity manager instance
*/
EntityManager createEntityManager();
/**
* Create a new application-managed EntityManager with properties
* @param map properties for the EntityManager
* @return entity manager instance
*/
EntityManager createEntityManager(Map map);
/**
* Create a new EntityManager with the specified synchronization type
* @param synchronizationType synchronization type
* @return entity manager instance
* @since 2.1
*/
EntityManager createEntityManager(SynchronizationType synchronizationType);
/**
* Create a new EntityManager with synchronization type and properties
* @param synchronizationType synchronization type
* @param map properties for the EntityManager
* @return entity manager instance
* @since 2.1
*/
EntityManager createEntityManager(SynchronizationType synchronizationType, Map map);
/**
* Get an instance of CriteriaBuilder for creating Criteria queries
* @return CriteriaBuilder instance
* @since 2.0
*/
CriteriaBuilder getCriteriaBuilder();
/**
* Return an instance of Metamodel interface for access to entity metadata
* @return Metamodel instance
* @since 2.0
*/
Metamodel getMetamodel();
/**
* Indicates whether the factory is open
* @return true if the factory is open
*/
boolean isOpen();
/**
* Close the factory
*/
void close();
/**
* Get the properties and associated values
* @return properties
* @since 2.0
*/
Map<String, Object> getProperties();
/**
* Access the cache that is associated with the factory
* @return Cache instance
* @since 2.0
*/
Cache getCache();
/**
* Return interface providing access to utility methods
* @return PersistenceUnitUtil instance
* @since 2.0
*/
PersistenceUnitUtil getPersistenceUnitUtil();
/**
* Define a named query
* @param name query name
* @param query Query or TypedQuery instance
* @since 2.1
*/
void addNamedQuery(String name, Query query);
/**
* Return an object of the specified type to allow access to provider-specific API
* @param cls the class of the object to be returned
* @return an instance of the specified class
* @since 2.1
*/
<T> T unwrap(Class<T> cls);
/**
* Add a named EntityGraph
* @param graphName name of the graph
* @param entityGraph EntityGraph instance
* @since 2.1
*/
<T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph);
}
/**
* Interface for persistence unit utility methods
* @since 2.0
*/
public interface PersistenceUnitUtil extends PersistenceUtil {
/**
* Determine the load state of an attribute belonging to the persistence unit
* @param entity entity instance
* @param attributeName name of the attribute
* @return true if the attribute is loaded
*/
boolean isLoaded(Object entity, String attributeName);
/**
* Determine the load state of an entity belonging to the persistence unit
* @param entity entity instance
* @return true if all EAGER attributes are loaded
*/
boolean isLoaded(Object entity);
/**
* Return the identifier of the entity
* @param entity entity instance
* @return the identifier
*/
Object getIdentifier(Object entity);
}Usage Example:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");
// Create entity managers
EntityManager em1 = emf.createEntityManager();
EntityManager em2 = emf.createEntityManager(SynchronizationType.UNSYNCHRONIZED);
// Get metamodel and criteria builder
Metamodel metamodel = emf.getMetamodel();
CriteriaBuilder cb = emf.getCriteriaBuilder();
// Access cache
Cache cache = emf.getCache();
cache.evictAll();
// Get entity identifier
PersistenceUnitUtil util = emf.getPersistenceUnitUtil();
Object id = util.getIdentifier(entity);
// Close when done
emf.close();Manage entity lifecycle and persistence context.
/**
* Interface for interacting with the persistence context
* @since 1.0
*/
public interface EntityManager extends AutoCloseable {
/**
* Make an instance managed and persistent
* @param entity entity instance
*/
void persist(Object entity);
/**
* Merge the state of the given entity into the current persistence context
* @param entity entity instance
* @return the managed instance
*/
<T> T merge(T entity);
/**
* Remove the entity instance
* @param entity entity instance
*/
void remove(Object entity);
/**
* Find by primary key
* @param entityClass entity class
* @param primaryKey primary key
* @return the found entity instance or null
*/
<T> T find(Class<T> entityClass, Object primaryKey);
/**
* Find by primary key with properties
* @param entityClass entity class
* @param primaryKey primary key
* @param properties standard and vendor-specific properties
* @return the found entity instance or null
* @since 2.0
*/
<T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties);
/**
* Find by primary key and lock
* @param entityClass entity class
* @param primaryKey primary key
* @param lockMode lock mode
* @return the found entity instance or null
* @since 2.0
*/
<T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode);
/**
* Find by primary key, lock, and properties
* @param entityClass entity class
* @param primaryKey primary key
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* @return the found entity instance or null
* @since 2.0
*/
<T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties);
/**
* Get a reference to the entity
* @param entityClass entity class
* @param primaryKey primary key
* @return the entity reference
*/
<T> T getReference(Class<T> entityClass, Object primaryKey);
/**
* Synchronize the persistence context to the underlying database
*/
void flush();
/**
* Set the flush mode for all objects in the persistence context
* @param flushMode flush mode
*/
void setFlushMode(FlushModeType flushMode);
/**
* Get the flush mode
* @return flush mode
*/
FlushModeType getFlushMode();
/**
* Lock an entity instance using the specified lock mode type
* @param entity entity instance
* @param lockMode lock mode
* @since 2.0
*/
void lock(Object entity, LockModeType lockMode);
/**
* Lock an entity instance with properties
* @param entity entity instance
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* @since 2.0
*/
void lock(Object entity, LockModeType lockMode, Map<String, Object> properties);
/**
* Refresh the state of the instance from the database
* @param entity entity instance
*/
void refresh(Object entity);
/**
* Refresh with properties
* @param entity entity instance
* @param properties standard and vendor-specific properties
* @since 2.0
*/
void refresh(Object entity, Map<String, Object> properties);
/**
* Refresh with lock mode
* @param entity entity instance
* @param lockMode lock mode
* @since 2.0
*/
void refresh(Object entity, LockModeType lockMode);
/**
* Refresh with lock mode and properties
* @param entity entity instance
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* @since 2.0
*/
void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties);
/**
* Clear the persistence context
*/
void clear();
/**
* Remove the given entity from the persistence context
* @param entity entity instance
* @since 2.0
*/
void detach(Object entity);
/**
* Check if the instance is a managed entity
* @param entity entity instance
* @return true if the entity is managed
*/
boolean contains(Object entity);
/**
* Get the current lock mode for the entity instance
* @param entity entity instance
* @return lock mode
* @since 2.0
*/
LockModeType getLockMode(Object entity);
/**
* Set an entity manager property or hint
* @param propertyName property name
* @param value property value
* @since 2.0
*/
void setProperty(String propertyName, Object value);
/**
* Get the properties and hints
* @return properties and hints
* @since 2.0
*/
Map<String, Object> getProperties();
/**
* Close the entity manager
*/
void close();
/**
* Determine whether the entity manager is open
* @return true if the entity manager is open
*/
boolean isOpen();
/**
* Return the resource-level EntityTransaction object
* @return EntityTransaction instance
*/
EntityTransaction getTransaction();
}Usage Example:
EntityManager em = emf.createEntityManager();
try {
// Persist new entity
User user = new User();
user.setName("Alice");
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
// Find entity
User found = em.find(User.class, 1L);
// Find with lock
User locked = em.find(User.class, 1L, LockModeType.PESSIMISTIC_WRITE);
// Merge detached entity
User detached = new User();
detached.setId(1L);
detached.setName("Bob");
em.getTransaction().begin();
User merged = em.merge(detached);
em.getTransaction().commit();
// Refresh entity
em.refresh(merged);
// Remove entity
em.getTransaction().begin();
em.remove(merged);
em.getTransaction().commit();
// Check if managed
boolean managed = em.contains(merged);
// Detach entity
em.detach(found);
// Clear persistence context
em.clear();
} finally {
em.close();
}Create and manage queries.
/**
* EntityManager query creation methods
*/
public interface EntityManager extends AutoCloseable {
/**
* Create an instance of Query for executing a JPQL query
* @param qlString JPQL query string
* @return Query instance
*/
Query createQuery(String qlString);
/**
* Create a typed query from a JPQL string
* @param qlString JPQL query string
* @param resultClass the type of the query result
* @return TypedQuery instance
* @since 2.0
*/
<T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass);
/**
* Create a query from a CriteriaQuery object
* @param criteriaQuery criteria query
* @return TypedQuery instance
* @since 2.0
*/
<T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery);
/**
* Create an update query from a CriteriaUpdate object
* @param updateQuery criteria update query
* @return Query instance
* @since 2.1
*/
Query createQuery(CriteriaUpdate updateQuery);
/**
* Create a delete query from a CriteriaDelete object
* @param deleteQuery criteria delete query
* @return Query instance
* @since 2.1
*/
Query createQuery(CriteriaDelete deleteQuery);
/**
* Create an instance of Query for executing a native SQL query
* @param sqlString native SQL query string
* @return Query instance
*/
Query createNativeQuery(String sqlString);
/**
* Create a native query that returns entities
* @param sqlString native SQL query string
* @param resultClass the class of the resulting entity
* @return Query instance
*/
Query createNativeQuery(String sqlString, Class resultClass);
/**
* Create a native query using a result set mapping
* @param sqlString native SQL query string
* @param resultSetMapping the name of the result set mapping
* @return Query instance
*/
Query createNativeQuery(String sqlString, String resultSetMapping);
/**
* Create a named query
* @param name the name of the query
* @return Query instance
*/
Query createNamedQuery(String name);
/**
* Create a typed named query
* @param name the name of the query
* @param resultClass the type of the query result
* @return TypedQuery instance
* @since 2.0
*/
<T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass);
/**
* Create a stored procedure query
* @param name name of the stored procedure in the database
* @return StoredProcedureQuery instance
* @since 2.1
*/
StoredProcedureQuery createStoredProcedureQuery(String name);
/**
* Create a stored procedure query with result class
* @param name name of the stored procedure
* @param resultClasses classes of the result
* @return StoredProcedureQuery instance
* @since 2.1
*/
StoredProcedureQuery createStoredProcedureQuery(String name, Class... resultClasses);
/**
* Create a stored procedure query with result set mapping
* @param name name of the stored procedure
* @param resultSetMappings names of the result set mappings
* @return StoredProcedureQuery instance
* @since 2.1
*/
StoredProcedureQuery createStoredProcedureQuery(String name, String... resultSetMappings);
/**
* Create a named stored procedure query
* @param name name of the query
* @return StoredProcedureQuery instance
* @since 2.1
*/
StoredProcedureQuery createNamedStoredProcedureQuery(String name);
/**
* Get the CriteriaBuilder instance
* @return CriteriaBuilder instance
* @since 2.0
*/
CriteriaBuilder getCriteriaBuilder();
/**
* Get the Metamodel instance
* @return Metamodel instance
* @since 2.0
*/
Metamodel getMetamodel();
}Usage Example:
EntityManager em = emf.createEntityManager();
// JPQL query
Query query = em.createQuery("SELECT u FROM User u WHERE u.name = :name");
query.setParameter("name", "Alice");
List users = query.getResultList();
// Typed JPQL query
TypedQuery<User> typedQuery = em.createQuery(
"SELECT u FROM User u WHERE u.active = true", User.class);
List<User> activeUsers = typedQuery.getResultList();
// Native SQL query
Query nativeQuery = em.createNativeQuery(
"SELECT * FROM users WHERE email LIKE ?", User.class);
nativeQuery.setParameter(1, "%@example.com");
List<User> emailUsers = nativeQuery.getResultList();
// Named query
TypedQuery<User> namedQuery = em.createNamedQuery("User.findByName", User.class);
namedQuery.setParameter("name", "Bob");
List<User> namedUsers = namedQuery.getResultList();
// Stored procedure query
StoredProcedureQuery spQuery = em.createStoredProcedureQuery("calculate_discount");
spQuery.registerStoredProcedureParameter(1, Long.class, ParameterMode.IN);
spQuery.registerStoredProcedureParameter(2, BigDecimal.class, ParameterMode.OUT);
spQuery.setParameter(1, 1L);
spQuery.execute();
BigDecimal discount = (BigDecimal) spQuery.getOutputParameterValue(2);Manage resource-local transactions.
/**
* Interface for resource-local entity transaction management
* @since 1.0
*/
public interface EntityTransaction {
/**
* Start a resource transaction
*/
void begin();
/**
* Commit the current resource transaction
*/
void commit();
/**
* Roll back the current resource transaction
*/
void rollback();
/**
* Mark the current transaction so that it can only be rolled back
*/
void setRollbackOnly();
/**
* Determine whether the transaction has been marked for rollback
* @return true if the transaction is marked for rollback
*/
boolean getRollbackOnly();
/**
* Indicate whether a transaction is in progress
* @return true if a transaction is active
*/
boolean isActive();
}
/**
* EntityManager transaction methods
*/
public interface EntityManager extends AutoCloseable {
/**
* Return the resource-level EntityTransaction object
* @return EntityTransaction instance
*/
EntityTransaction getTransaction();
/**
* Indicate to the entity manager that a JTA transaction is active
* @since 2.0
*/
void joinTransaction();
/**
* Determine whether the entity manager is joined to the current transaction
* @return true if joined to transaction
* @since 2.1
*/
boolean isJoinedToTransaction();
}Usage Example:
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
User user = new User();
user.setName("Alice");
em.persist(user);
// Update operation
User existing = em.find(User.class, 1L);
existing.setEmail("alice@example.com");
tx.commit();
} catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
throw e;
} finally {
em.close();
}
// Mark for rollback only
tx.begin();
try {
// Some operation
if (someCondition) {
tx.setRollbackOnly();
}
} finally {
if (tx.getRollbackOnly()) {
tx.rollback();
} else {
tx.commit();
}
}Control fetching strategies dynamically.
/**
* EntityManager entity graph methods
*/
public interface EntityManager extends AutoCloseable {
/**
* Return a mutable EntityGraph for entity type
* @param rootType entity class
* @return EntityGraph instance
* @since 2.1
*/
<T> EntityGraph<T> createEntityGraph(Class<T> rootType);
/**
* Return a mutable copy of named EntityGraph
* @param graphName name of an entity graph
* @return EntityGraph instance
* @since 2.1
*/
EntityGraph<?> createEntityGraph(String graphName);
/**
* Return a named EntityGraph
* @param graphName name of an entity graph
* @return EntityGraph instance
* @since 2.1
*/
EntityGraph<?> getEntityGraph(String graphName);
/**
* Return all named EntityGraphs for the entity
* @param entityClass entity class
* @return list of EntityGraph instances
* @since 2.1
*/
<T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass);
}
/**
* Interface for entity graph dynamic fetch configuration
* @since 2.1
*/
public interface EntityGraph<T> {
/**
* Return the name of the EntityGraph
* @return entity graph name
*/
String getName();
/**
* Add one or more attribute nodes to the entity graph
* @param attributeName attribute name
*/
void addAttributeNodes(String... attributeName);
/**
* Add attribute nodes using metamodel attributes
* @param attribute metamodel attribute
*/
void addAttributeNodes(Attribute<T, ?>... attribute);
/**
* Add a node to the graph that corresponds to a managed type
* @param attribute attribute
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(Attribute<T, X> attribute);
/**
* Add a node to the graph with inheritance
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
*/
<X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type);
/**
* Add a node using attribute name
* @param attributeName attribute name
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(String attributeName);
/**
* Add a node using attribute name and type
* @param attributeName attribute name
* @param type entity subclass
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(String attributeName, Class<X> type);
/**
* Add a node that corresponds to a map key
* @param attribute attribute
* @return subgraph for the key attribute
*/
<X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute);
/**
* Add a node for map key with type
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the key attribute
*/
<X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type);
/**
* Add a node for map key using attribute name
* @param attributeName attribute name
* @return subgraph for the key attribute
*/
<X> Subgraph<X> addKeySubgraph(String attributeName);
/**
* Add a node for map key using attribute name and type
* @param attributeName attribute name
* @param type entity subclass
* @return subgraph for the key attribute
*/
<X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type);
/**
* Add a subclass subgraph
* @param type entity subclass
* @return subgraph for the subclass
*/
<X extends T> Subgraph<X> addSubclassSubgraph(Class<X> type);
/**
* Return the attribute nodes of this entity graph
* @return list of attribute nodes
*/
List<AttributeNode<?>> getAttributeNodes();
}
/**
* Interface for entity graph attribute node
* @since 2.1
*/
public interface AttributeNode<T> {
/**
* Return the name of the referenced attribute
* @return attribute name
*/
String getAttributeName();
/**
* Return the subgraphs associated with this attribute node
* @return map of subgraphs
*/
Map<Class, Subgraph> getSubgraphs();
/**
* Return the key subgraphs associated with this attribute node
* @return map of key subgraphs
*/
Map<Class, Subgraph> getKeySubgraphs();
}
/**
* Interface for entity subgraph
* @since 2.1
*/
public interface Subgraph<T> {
/**
* Add attribute nodes to the subgraph
* @param attributeName attribute name
*/
void addAttributeNodes(String... attributeName);
/**
* Add attribute nodes using metamodel attributes
* @param attribute metamodel attribute
*/
void addAttributeNodes(Attribute<T, ?>... attribute);
/**
* Add a nested subgraph
* @param attribute attribute
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(Attribute<T, X> attribute);
/**
* Add a nested subgraph with type
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
*/
<X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type);
/**
* Add a nested subgraph using attribute name
* @param attributeName attribute name
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(String attributeName);
/**
* Add a nested subgraph using attribute name and type
* @param attributeName attribute name
* @param type entity subclass
* @return subgraph for the attribute
*/
<X> Subgraph<X> addSubgraph(String attributeName, Class<X> type);
/**
* Add a subgraph for map key
* @param attribute attribute
* @return subgraph for the key
*/
<X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute);
/**
* Add a subgraph for map key with type
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the key
*/
<X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type);
/**
* Add a subgraph for map key using attribute name
* @param attributeName attribute name
* @return subgraph for the key
*/
<X> Subgraph<X> addKeySubgraph(String attributeName);
/**
* Add a subgraph for map key using attribute name and type
* @param attributeName attribute name
* @param type entity subclass
* @return subgraph for the key
*/
<X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type);
/**
* Return the attribute nodes of this subgraph
* @return list of attribute nodes
*/
List<AttributeNode<?>> getAttributeNodes();
/**
* Return the type of this subgraph
* @return class type
*/
Class<T> getClassType();
}Usage Example:
EntityManager em = emf.createEntityManager();
// Create entity graph
EntityGraph<User> graph = em.createEntityGraph(User.class);
graph.addAttributeNodes("name", "email");
graph.addSubgraph("orders").addAttributeNodes("orderDate", "totalAmount");
// Use entity graph with find
Map<String, Object> properties = new HashMap<>();
properties.put("jakarta.persistence.fetchgraph", graph);
User user = em.find(User.class, 1L, properties);
// Use entity graph with query
TypedQuery<User> query = em.createQuery("SELECT u FROM User u", User.class);
query.setHint("jakarta.persistence.loadgraph", graph);
List<User> users = query.getResultList();
// Named entity graph
EntityGraph<?> namedGraph = em.getEntityGraph("User.detail");Get the EntityManagerFactory and unwrap to provider-specific interfaces.
/**
* EntityManager factory and utility methods
*/
public interface EntityManager extends AutoCloseable {
/**
* Return the entity manager factory for this entity manager
* @return EntityManagerFactory instance
* @since 2.0
*/
EntityManagerFactory getEntityManagerFactory();
/**
* Return an object of the specified type to allow access to provider-specific API
* @param cls the class of the object to be returned
* @return an instance of the specified class
* @since 2.0
*/
<T> T unwrap(Class<T> cls);
/**
* Return the underlying provider object
* @return provider object
*/
Object getDelegate();
}Usage Example:
EntityManager em = emf.createEntityManager();
// Get factory
EntityManagerFactory factory = em.getEntityManagerFactory();
// Unwrap to provider-specific interface (e.g., Hibernate Session)
// Session session = em.unwrap(Session.class);
// Get delegate
Object delegate = em.getDelegate();Install with Tessl CLI
npx tessl i tessl/maven-jakarta-persistence--jakarta-persistence-api