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

org.hibernate.collection.internal.PersistentIdentifierBag Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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.collection.internal;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.Type;

/**
 * An IdentifierBag implements "bag" semantics more efficiently than
 * a regular Bag by adding a synthetic identifier column to the
 * table. This identifier is unique for all rows in the table, allowing very
 * efficient updates and deletes. The value of the identifier is never exposed
 * to the application.
*
* IdentifierBags may not be used for a many-to-one association. * Furthermore, there is no reason to use inverse="true". * * @author Gavin King */ public class PersistentIdentifierBag extends AbstractPersistentCollection implements List { protected List values; protected Map identifiers; /** * Constructs a PersistentIdentifierBag. This form needed for SOAP libraries, etc */ @SuppressWarnings("UnusedDeclaration") public PersistentIdentifierBag() { } /** * Constructs a PersistentIdentifierBag. * * @param session The session */ public PersistentIdentifierBag(SharedSessionContractImplementor session) { super( session ); } /** * Constructs a PersistentIdentifierBag. * * @param session The session * @deprecated {@link #PersistentIdentifierBag(SharedSessionContractImplementor)} should be used instead. */ @Deprecated public PersistentIdentifierBag(SessionImplementor session) { this( (SharedSessionContractImplementor) session ); } /** * Constructs a PersistentIdentifierBag. * * @param session The session * @param coll The base elements */ @SuppressWarnings("unchecked") public PersistentIdentifierBag(SharedSessionContractImplementor session, Collection coll) { super( session ); if (coll instanceof List) { values = (List) coll; } else { values = new ArrayList<>(); for ( Object element : coll ) { values.add( element ); } } setInitialized(); setDirectlyAccessible( true ); identifiers = new HashMap<>(); } /** * Constructs a PersistentIdentifierBag. * * @param session The session * @param coll The base elements * @deprecated {@link #PersistentIdentifierBag(SharedSessionContractImplementor, Collection)} should be used instead. */ @Deprecated public PersistentIdentifierBag(SessionImplementor session, Collection coll) { this( (SharedSessionContractImplementor) session, coll ); } @Override public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner) throws HibernateException { final Serializable[] array = (Serializable[]) disassembled; final int size = array.length; beforeInitialize( persister, size ); for ( int i = 0; i < size; i+=2 ) { identifiers.put( (i/2), persister.getIdentifierType().assemble( array[i], getSession(), owner ) ); values.add( persister.getElementType().assemble( array[i+1], getSession(), owner ) ); } } @Override public Object getIdentifier(Object entry, int i) { return identifiers.get( i ); } @Override public boolean isWrapper(Object collection) { return values==collection; } @Override public boolean add(Object o) { write(); values.add( o ); return true; } @Override public void clear() { initialize( true ); if ( ! values.isEmpty() || ! identifiers.isEmpty() ) { values.clear(); identifiers.clear(); dirty(); } } @Override public boolean contains(Object o) { read(); return values.contains( o ); } @Override public boolean containsAll(Collection c) { read(); return values.containsAll( c ); } @Override public boolean isEmpty() { return readSize() ? getCachedSize()==0 : values.isEmpty(); } @Override public Iterator iterator() { read(); return new IteratorProxy( values.iterator() ); } @Override public boolean remove(Object o) { initialize( true ); final int index = values.indexOf( o ); if ( index >= 0 ) { beforeRemove( index ); values.remove( index ); elementRemoved = true; dirty(); return true; } else { return false; } } @Override public boolean removeAll(Collection c) { if ( c.size() > 0 ) { boolean result = false; for ( Object element : c ) { if ( remove( element ) ) { result = true; } } return result; } else { return false; } } @Override public boolean retainAll(Collection c) { initialize( true ); if ( values.retainAll( c ) ) { dirty(); return true; } else { return false; } } @Override public int size() { return readSize() ? getCachedSize() : values.size(); } @Override public Object[] toArray() { read(); return values.toArray(); } @Override public Object[] toArray(Object[] a) { read(); return values.toArray( a ); } @Override public void beforeInitialize(CollectionPersister persister, int anticipatedSize) { identifiers = anticipatedSize <= 0 ? new HashMap<>() : new HashMap<>( anticipatedSize + 1 + (int) ( anticipatedSize * .75f ), .75f ); values = anticipatedSize <= 0 ? new ArrayList<>() : new ArrayList<>( anticipatedSize ); } @Override public Serializable disassemble(CollectionPersister persister) throws HibernateException { final Serializable[] result = new Serializable[ values.size() * 2 ]; int i = 0; for ( int j=0; j< values.size(); j++ ) { final Object value = values.get( j ); result[i++] = persister.getIdentifierType().disassemble( identifiers.get( j ), getSession(), null ); result[i++] = persister.getElementType().disassemble( value, getSession(), null ); } return result; } @Override public boolean empty() { return values.isEmpty(); } @Override public Iterator entries(CollectionPersister persister) { return values.iterator(); } @Override public boolean entryExists(Object entry, int i) { return entry!=null; } @Override public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { final Type elementType = persister.getElementType(); final Map snap = (Map) getSnapshot(); if ( snap.size()!= values.size() ) { return false; } for ( int i=0; i 0 ) { for ( Object element : c ) { add( index++, element ); } return true; } else { return false; } } @Override public Object get(int index) { read(); return values.get( index ); } @Override public int indexOf(Object o) { read(); return values.indexOf( o ); } @Override public int lastIndexOf(Object o) { read(); return values.lastIndexOf( o ); } @Override public ListIterator listIterator() { read(); return new ListIteratorProxy( values.listIterator() ); } @Override public ListIterator listIterator(int index) { read(); return new ListIteratorProxy( values.listIterator( index ) ); } private void beforeRemove(int index) { final Object removedId = identifiers.get( index ); final int last = values.size()-1; for ( int i=index; i 0 ) { write(); return values.addAll( c ); } else { return false; } } @Override public void afterRowInsert( CollectionPersister persister, Object entry, int i) throws HibernateException { //TODO: if we are using identity columns, fetch the identifier } }