All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.Hibernate Maven / Gradle / Ivy

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Supplier;

import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.collection.spi.PersistentBag;
import org.hibernate.collection.spi.PersistentList;
import org.hibernate.collection.spi.PersistentMap;
import org.hibernate.collection.spi.PersistentSet;
import org.hibernate.collection.spi.PersistentSortedMap;
import org.hibernate.collection.spi.PersistentSortedSet;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;

/**
 * Various utility functions for working with proxies and lazy collection references.
 * 

* Operations like {@link #isInitialized(Object)} and {@link #initialize(Object)} are * of general purpose. But {@link #createDetachedProxy(SessionFactory, Class, Object)} * and {@link CollectionInterface#createDetachedProxy(SessionFactory, Class, Object)} * are intended for use by generic code that must materialize an "amputated" graph of * Hibernate entities. (For example, a library which deserializes entities from JSON.) *

* Graphs of Hibernate entities obtained from a {@link Session} are usually in an * amputated form, with associations and collections replaced by proxies and lazy * collections. (That is, by instances of the internal types {@link HibernateProxy} * and {@link PersistentCollection}.) These objects are fully serializable using * Java serialization, but can cause discomfort when working with custom serialization * libraries. Therefore, this class defines operations that may be used to write code * that completely removes the amputated leaves of the graph (the proxies) during * serialization, and rematerializes and reattaches them during deserialization. It's * possible, in principle, to use these operations, together with reflection, or with * the Hibernate metamodel, to write such generic code for any given serialization * library, but the details depend on what facilities the library itself offers for * the program to intervene in the process of serialization and of deserialization. * * @author Gavin King */ public final class Hibernate { /** * Cannot be instantiated. */ private Hibernate() { throw new UnsupportedOperationException(); } /** * Force initialization of a proxy or persistent collection. In the case of a * many-valued association, only the collection itself is initialized. It is not * guaranteed that the associated entities held within the collection will be * initialized. * * @param proxy a persistable object, proxy, persistent collection or {@code null} * @throws HibernateException if the proxy cannot be initialized at this time, * for example, if the {@code Session} was closed */ public static void initialize(Object proxy) throws HibernateException { if ( proxy == null ) { return; } if ( proxy instanceof HibernateProxy ) { ( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize(); } else if ( proxy instanceof PersistentCollection ) { ( (PersistentCollection) proxy ).forceInitialization(); } else if ( proxy instanceof PersistentAttributeInterceptable ) { final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) proxy; final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor(); if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { ( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( proxy, null ); } } } /** * Check if the proxy or persistent collection is initialized. * * @param proxy a persistable object, proxy, persistent collection or {@code null} * @return true if the argument is already initialized, or is not a proxy or collection */ public static boolean isInitialized(Object proxy) { if ( proxy instanceof HibernateProxy ) { return !( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUninitialized(); } else if ( proxy instanceof PersistentAttributeInterceptable ) { final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) proxy ).$$_hibernate_getInterceptor(); return !(interceptor instanceof EnhancementAsProxyLazinessInterceptor); } else if ( proxy instanceof PersistentCollection ) { return ( (PersistentCollection) proxy ).wasInitialized(); } else { return true; } } /** * Get the true, underlying class of a proxied persistent class. This operation * will initialize a proxy by side effect. * * @param proxy an entity instance or proxy * @return the true class of the instance */ @SuppressWarnings("unchecked") public static Class getClass(T proxy) { Class result; if ( proxy instanceof HibernateProxy ) { result = ( (HibernateProxy) proxy ).getHibernateLazyInitializer() .getImplementation() .getClass(); } else { result = proxy.getClass(); } return (Class) result; } /** * Check if the property is initialized. If the named property does not exist or * is not persistent, this method always returns {@code true}. * * @param proxy The potential proxy * @param propertyName the name of a persistent attribute of the object * @return true if the named property of the object is not listed as uninitialized; * false otherwise */ public static boolean isPropertyInitialized(Object proxy, String propertyName) { final Object entity; if ( proxy instanceof HibernateProxy ) { final LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer(); if ( li.isUninitialized() ) { return false; } else { entity = li.getImplementation(); } } else { entity = proxy; } if ( entity instanceof PersistentAttributeInterceptable ) { PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); if ( interceptor instanceof BytecodeLazyAttributeInterceptor ) { return ( (BytecodeLazyAttributeInterceptor) interceptor ).isAttributeLoaded( propertyName ); } } return true; } /** * If the given object is not a proxy, return it. But, if it is a proxy, ensure * that the proxy is initialized, and return a direct reference to its proxied * entity object. * * @param proxy an object which might be a proxy for an entity * @return a reference that is never proxied * * @throws LazyInitializationException if this operation is called on an * uninitialized proxy that is not associated with an open session. */ public static Object unproxy(Object proxy) { if ( proxy instanceof HibernateProxy ) { HibernateProxy hibernateProxy = (HibernateProxy) proxy; LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); return initializer.getImplementation(); } else { return proxy; } } /** * If the given object is not a proxy, cast it to the given type, and return it. * But, if it is a proxy, ensure that the proxy is initialized, and return a * direct reference to its proxied entity object, after casting to the given type. * * @param proxy an object which might be a proxy for an entity * @param entityClass an entity type to cast to * @return a reference that is never proxied * * @throws LazyInitializationException if this operation is called on an * uninitialized proxy that is not associated with an open session. */ public static T unproxy(T proxy, Class entityClass) { return entityClass.cast( unproxy( proxy ) ); } /** * Obtain a detached, uninitialized reference (a proxy) for a persistent entity with * the given identifier. * * The returned proxy is not associated with any session, and cannot be initialized * by calling {@link #initialize(Object)}. It can be used to represent a reference to * the entity when working with a detached object graph. * * @param sessionFactory the session factory with which the entity is associated * @param entityClass the entity class * @param id the id of the persistent entity instance * * @return a detached uninitialized proxy */ @SuppressWarnings("unchecked") public static E createDetachedProxy(SessionFactory sessionFactory, Class entityClass, Object id) { final EntityPersister persister = sessionFactory.unwrap(SessionFactoryImplementor.class) .getRuntimeMetamodels() .getMappingMetamodel() .findEntityDescriptor(entityClass); if (persister==null) { throw new UnknownEntityTypeException("unknown entity type"); } return (E) persister.createProxy(id, null); } /** * Operations for obtaining references to persistent collections of a certain type. * * @param the type of collection, for example, {@code List<User>} */ public static final class CollectionInterface { private final Supplier detached; private final Supplier created; private CollectionInterface(Supplier detached, Supplier created) { this.detached = detached; this.created = created; } /** * Obtain a detached, uninitialized persistent collection of the type represented * by this object. * * The returned wrapper object is not associated with any session, and cannot be * initialized by calling {@link #initialize(Object)}. It can be used to represent * an uninitialized collection when working with a detached object graph. * * @return an uninitialized persistent collection */ public C createDetachedInstance() { return detached.get(); } /** * Instantiate an empty collection of the type represented by this object. * * @return a newly-instantiated empty collection */ public C createNewInstance() { return created.get(); } } /** * Obtain an instance of {@link CollectionInterface} representing persistent bags * of a given element type. * * @param the element type */ public static CollectionInterface> bag() { return new CollectionInterface<>(PersistentBag::new, ArrayList::new); } /** * Obtain an instance of {@link CollectionInterface} representing persistent sets * of a given element type. * * @param the element type */ public static CollectionInterface> set() { return new CollectionInterface<>(PersistentSet::new, HashSet::new); } /** * Obtain an instance of {@link CollectionInterface} representing persistent lists * of a given element type. * * @param the element type */ public static CollectionInterface> list() { return new CollectionInterface<>(PersistentList::new, ArrayList::new); } /** * Obtain an instance of {@link CollectionInterface} representing persistent maps * of a given key and value types. * * @param the key type * @param the value type */ public static CollectionInterface> map() { return new CollectionInterface<>(PersistentMap::new, HashMap::new); } /** * Obtain an instance of {@link CollectionInterface} representing sorted persistent sets * of a given element type. * * @param the element type */ public static CollectionInterface> sortedSet() { return new CollectionInterface<>(PersistentSortedSet::new, TreeSet::new); } /** * Obtain an instance of {@link CollectionInterface} representing sorted persistent maps * of a given key and value types. * * @param the key type * @param the value type * */ public static CollectionInterface> sortedMap() { return new CollectionInterface<>(PersistentSortedMap::new, TreeMap::new); } /** * Obtain an instance of {@link CollectionInterface} representing persistent collections * of the given type. * * @param collectionClass the Java class object representing the collection type */ @SuppressWarnings("unchecked") public static CollectionInterface collection(Class collectionClass) { if (collectionClass == List.class) { return (CollectionInterface) list(); } else if (collectionClass == Set.class) { return (CollectionInterface) set(); } else if (collectionClass == Map.class) { return (CollectionInterface) map(); } if (collectionClass == SortedMap.class) { return (CollectionInterface) sortedMap(); } else if (collectionClass == SortedSet.class) { return (CollectionInterface) sortedSet(); } else if (collectionClass == Collection.class) { return (CollectionInterface) bag(); } else { throw new IllegalArgumentException("illegal collection interface type"); } } }