📄 collectiontype.java
字号:
// $Id: CollectionType.java 11302 2007-03-19 20:44:11Z steve.ebersole@jboss.com $package org.hibernate.type;import java.io.Serializable;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.List;import java.util.Map;import org.dom4j.Element;import org.dom4j.Node;import org.hibernate.EntityMode;import org.hibernate.Hibernate;import org.hibernate.HibernateException;import org.hibernate.MappingException;import org.hibernate.collection.PersistentCollection;import org.hibernate.engine.CollectionKey;import org.hibernate.engine.EntityEntry;import org.hibernate.engine.Mapping;import org.hibernate.engine.PersistenceContext;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.engine.SessionImplementor;import org.hibernate.persister.collection.CollectionPersister;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.persister.entity.Joinable;import org.hibernate.proxy.HibernateProxy;import org.hibernate.proxy.LazyInitializer;import org.hibernate.util.ArrayHelper;import org.hibernate.util.MarkerObject;/** * A type that handles Hibernate <tt>PersistentCollection</tt>s (including arrays). * * @author Gavin King */public abstract class CollectionType extends AbstractType implements AssociationType { private static final Object NOT_NULL_COLLECTION = new MarkerObject( "NOT NULL COLLECTION" ); public static final Object UNFETCHED_COLLECTION = new MarkerObject( "UNFETCHED COLLECTION" ); private final String role; private final String foreignKeyPropertyName; private final boolean isEmbeddedInXML; public CollectionType(String role, String foreignKeyPropertyName, boolean isEmbeddedInXML) { this.role = role; this.foreignKeyPropertyName = foreignKeyPropertyName; this.isEmbeddedInXML = isEmbeddedInXML; } public boolean isEmbeddedInXML() { return isEmbeddedInXML; } public String getRole() { return role; } public Object indexOf(Object collection, Object element) { throw new UnsupportedOperationException( "generic collections don't have indexes" ); } public boolean contains(Object collection, Object childObject, SessionImplementor session) { // we do not have to worry about queued additions to uninitialized // collections, since they can only occur for inverse collections! Iterator elems = getElementsIterator( collection, session ); while ( elems.hasNext() ) { Object element = elems.next(); // worrying about proxies is perhaps a little bit of overkill here... if ( element instanceof HibernateProxy ) { LazyInitializer li = ( (HibernateProxy) element ).getHibernateLazyInitializer(); if ( !li.isUninitialized() ) element = li.getImplementation(); } if ( element == childObject ) return true; } return false; } public boolean isCollectionType() { return true; } public final boolean isEqual(Object x, Object y, EntityMode entityMode) { return x == y || ( x instanceof PersistentCollection && ( (PersistentCollection) x ).isWrapper( y ) ) || ( y instanceof PersistentCollection && ( (PersistentCollection) y ).isWrapper( x ) ); } public int compare(Object x, Object y, EntityMode entityMode) { return 0; // collections cannot be compared } public int getHashCode(Object x, EntityMode entityMode) { throw new UnsupportedOperationException( "cannot perform lookups on collections" ); } /** * Instantiate an uninitialized collection wrapper or holder. Callers MUST add the holder to the * persistence context! * * @param session The session from which the request is originating. * @param persister The underlying collection persister (metadata) * @param key The owner key. * @return The instantiated collection. */ public abstract PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key); public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner) throws SQLException { return nullSafeGet( rs, new String[] { name }, session, owner ); } public Object nullSafeGet(ResultSet rs, String[] name, SessionImplementor session, Object owner) throws HibernateException, SQLException { return resolve( null, session, owner ); } public final void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) throws HibernateException, SQLException { //NOOP } public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { } public int[] sqlTypes(Mapping session) throws MappingException { return ArrayHelper.EMPTY_INT_ARRAY; } public int getColumnSpan(Mapping session) throws MappingException { return 0; } public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { if ( value == null ) { return "null"; } else if ( !Hibernate.isInitialized( value ) ) { return "<uninitialized>"; } else { return renderLoggableString( value, factory ); } } protected String renderLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException { if ( Element.class.isInstance( value ) ) { // for DOM4J "collections" only // TODO: it would be better if this was done at the higher level by Printer return ( ( Element ) value ).asXML(); } else { List list = new ArrayList(); Type elemType = getElementType( factory ); Iterator iter = getElementsIterator( value ); while ( iter.hasNext() ) { list.add( elemType.toLoggableString( iter.next(), factory ) ); } return list.toString(); } } public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) throws HibernateException { return value; } public String getName() { return getReturnedClass().getName() + '(' + getRole() + ')'; } /** * Get an iterator over the element set of the collection, which may not yet be wrapped * * @param collection The collection to be iterated * @param session The session from which the request is originating. * @return The iterator. */ public Iterator getElementsIterator(Object collection, SessionImplementor session) { if ( session.getEntityMode()==EntityMode.DOM4J ) { final SessionFactoryImplementor factory = session.getFactory(); final CollectionPersister persister = factory.getCollectionPersister( getRole() ); final Type elementType = persister.getElementType(); List elements = ( (Element) collection ).elements( persister.getElementNodeName() ); ArrayList results = new ArrayList(); for ( int i=0; i<elements.size(); i++ ) { Element value = (Element) elements.get(i); results.add( elementType.fromXMLNode( value, factory ) ); } return results.iterator(); } else { return getElementsIterator(collection); } } /** * Get an iterator over the element set of the collection in POJO mode * * @param collection The collection to be iterated * @return The iterator. */ protected Iterator getElementsIterator(Object collection) { return ( (Collection) collection ).iterator(); } public boolean isMutable() { return false; } public Serializable disassemble(Object value, SessionImplementor session, Object owner) throws HibernateException { //remember the uk value //This solution would allow us to eliminate the owner arg to disassemble(), but //what if the collection was null, and then later had elements added? seems unsafe //session.getPersistenceContext().getCollectionEntry( (PersistentCollection) value ).getKey(); final Serializable key = getKeyOfOwner(owner, session); if (key==null) { return null; } else { return getPersister(session) .getKeyType() .disassemble( key, session, owner ); } } public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException { //we must use the "remembered" uk value, since it is //not available from the EntityEntry during assembly if (cached==null) { return null; } else { final Serializable key = (Serializable) getPersister(session) .getKeyType() .assemble( cached, session, owner); return resolveKey( key, session, owner ); } } /** * Is the owning entity versioned? * * @param session The session from which the request is originating. * @return True if the collection owner is versioned; false otherwise. * @throws org.hibernate.MappingException Indicates our persister could not be located. */ private boolean isOwnerVersioned(SessionImplementor session) throws MappingException { return getPersister( session ).getOwnerEntityPersister().isVersioned(); } /** * Get our underlying collection persister (using the session to access the * factory). * * @param session The session from which the request is originating. * @return The underlying collection persister */ private CollectionPersister getPersister(SessionImplementor session) { return session.getFactory().getCollectionPersister( role ); } public boolean isDirty(Object old, Object current, SessionImplementor session) throws HibernateException { // collections don't dirty an unversioned parent entity // TODO: I don't really like this implementation; it would be better if // this was handled by searchForDirtyCollections() return isOwnerVersioned( session ) && super.isDirty( old, current, session ); // return false; } public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) throws HibernateException { return isDirty(old, current, session); } /** * Wrap the naked collection instance in a wrapper, or instantiate a * holder. Callers <b>MUST</b> add the holder to the persistence context! * * @param session The session from which the request is originating. * @param collection The bare collection to be wrapped. * @return The wrapped collection. */ public abstract PersistentCollection wrap(SessionImplementor session, Object collection); /** * Note: return true because this type is castable to <tt>AssociationType</tt>. Not because * all collections are associations. */ public boolean isAssociationType() { return true; } public ForeignKeyDirection getForeignKeyDirection() { return ForeignKeyDirection.FOREIGN_KEY_TO_PARENT; } /** * Get the key value from the owning entity instance, usually the identifier, but might be some * other unique key, in the case of property-ref * * @param owner The collection owner * @param session The session from which the request is originating. * @return The collection owner's key */ public Serializable getKeyOfOwner(Object owner, SessionImplementor session) { EntityEntry entityEntry = session.getPersistenceContext().getEntry( owner ); if ( entityEntry == null ) return null; // This just handles a particular case of component // projection, perhaps get rid of it and throw an exception if ( foreignKeyPropertyName == null ) { return entityEntry.getId(); } else { // TODO: at the point where we are resolving collection references, we don't // know if the uk value has been resolved (depends if it was earlier or // later in the mapping document) - now, we could try and use e.getStatus() // to decide to semiResolve(), trouble is that initializeEntity() reuses // the same array for resolved and hydrated values Object id; if ( entityEntry.getLoadedState() != null ) { id = entityEntry.getLoadedValue( foreignKeyPropertyName ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -