org.hibernate.collection.internal.PersistentSet 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.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.Set;
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;
/**
* A persistent wrapper for a java.util.Set. The underlying
* collection is a HashSet.
*
* @see java.util.HashSet
* @author Gavin King
*/
public class PersistentSet extends AbstractPersistentCollection implements java.util.Set {
protected Set set;
protected transient List tempList;
/**
* Empty constructor.
*
* Note: this form is not ever ever ever used by Hibernate; it is, however,
* needed for SOAP libraries and other such marshalling code.
*/
public PersistentSet() {
// intentionally empty
}
/**
* Constructor matching super. Instantiates a lazy set (the underlying
* set is un-initialized).
*
* @param session The session to which this set will belong.
*/
public PersistentSet(SharedSessionContractImplementor session) {
super( session );
}
/**
* Instantiates a lazy set (the underlying set is un-initialized).
*
* @param session The session to which this set will belong.
* @deprecated {@link #PersistentSet(SharedSessionContractImplementor)} should be used instead.
*/
@Deprecated
public PersistentSet(SessionImplementor session) {
this( (SharedSessionContractImplementor) session );
}
/**
* Instantiates a non-lazy set (the underlying set is constructed
* from the incoming set reference).
*
* @param session The session to which this set will belong.
* @param set The underlying set data.
*/
public PersistentSet(SharedSessionContractImplementor session, java.util.Set set) {
super( session );
// Sets can be just a view of a part of another collection.
// do we need to copy it to be sure it won't be changing
// underneath us?
// ie. this.set.addAll(set);
this.set = set;
setInitialized();
setDirectlyAccessible( true );
}
/**
* Instantiates a non-lazy set (the underlying set is constructed
* from the incoming set reference).
*
* @param session The session to which this set will belong.
* @param set The underlying set data.
* @deprecated {@link #PersistentSet(SharedSessionContractImplementor, java.util.Set)} should be used instead.
*/
@Deprecated
public PersistentSet(SessionImplementor session, java.util.Set set) {
this( (SharedSessionContractImplementor) session, set );
}
@Override
@SuppressWarnings( {"unchecked"})
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
final HashMap clonedSet = new HashMap( set.size() );
for ( Object aSet : set ) {
final Object copied = persister.getElementType().deepCopy( aSet, persister.getFactory() );
clonedSet.put( copied, copied );
}
return clonedSet;
}
@Override
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
final java.util.Map sn = (java.util.Map) snapshot;
return getOrphans( sn.keySet(), set, entityName, getSession() );
}
@Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
final Type elementType = persister.getElementType();
final java.util.Map sn = (java.util.Map) getSnapshot();
if ( sn.size()!=set.size() ) {
return false;
}
else {
for ( Object test : set ) {
final Object oldValue = sn.get( test );
if ( oldValue == null || elementType.isDirty( oldValue, test, getSession() ) ) {
return false;
}
}
return true;
}
}
@Override
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (java.util.Map) snapshot ).isEmpty();
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.set = (Set) persister.getCollectionType().instantiate( anticipatedSize );
}
@Override
@SuppressWarnings("unchecked")
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 ( Serializable arrayElement : array ) {
final Object assembledArrayElement = persister.getElementType().assemble( arrayElement, getSession(), owner );
if ( assembledArrayElement != null ) {
set.add( assembledArrayElement );
}
}
}
@Override
public boolean empty() {
return set.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public int size() {
return readSize() ? getCachedSize() : set.size();
}
@Override
@SuppressWarnings("unchecked")
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : set.isEmpty();
}
@Override
public boolean contains(Object object) {
final Boolean exists = readElementExistence( object );
return exists == null
? set.contains( object )
: exists;
}
@Override
@SuppressWarnings("unchecked")
public Iterator iterator() {
read();
return new IteratorProxy( set.iterator() );
}
@Override
@SuppressWarnings("unchecked")
public Object[] toArray() {
read();
return set.toArray();
}
@Override
@SuppressWarnings("unchecked")
public Object[] toArray(Object[] array) {
read();
return set.toArray( array );
}
@Override
public boolean add(Object value) {
final Boolean exists = isOperationQueueEnabled() ? readElementExistence( value ) : null;
if ( exists == null ) {
initialize( true );
if ( set.add( value ) ) {
dirty();
return true;
}
else {
return false;
}
}
else if ( exists ) {
return false;
}
else {
queueOperation( new SimpleAdd( value ) );
return true;
}
}
@Override
public boolean remove(Object value) {
final Boolean exists = isPutQueueEnabled() ? readElementExistence( value ) : null;
if ( exists == null ) {
initialize( true );
if ( set.remove( value ) ) {
elementRemoved = true;
dirty();
return true;
}
else {
return false;
}
}
else if ( exists ) {
elementRemoved = true;
queueOperation( new SimpleRemove( value ) );
return true;
}
else {
return false;
}
}
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection coll) {
read();
return set.containsAll( coll );
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection coll) {
if ( coll.size() > 0 ) {
initialize( true );
if ( set.addAll( coll ) ) {
dirty();
return true;
}
else {
return false;
}
}
else {
return false;
}
}
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection coll) {
initialize( true );
if ( set.retainAll( coll ) ) {
dirty();
return true;
}
else {
return false;
}
}
@Override
@SuppressWarnings("unchecked")
public boolean removeAll(Collection coll) {
if ( coll.size() > 0 ) {
initialize( true );
if ( set.removeAll( coll ) ) {
elementRemoved = true;
dirty();
return true;
}
else {
return false;
}
}
else {
return false;
}
}
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
}
else {
initialize( true );
if ( !set.isEmpty() ) {
set.clear();
dirty();
}
}
}
@Override
@SuppressWarnings("unchecked")
public String toString() {
read();
return set.toString();
}
@Override
@SuppressWarnings("unchecked")
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
CollectionAliases descriptor,
Object owner) throws HibernateException, SQLException {
final Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
if ( element != null ) {
tempList.add( element );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public void beginRead() {
super.beginRead();
tempList = new ArrayList();
}
@Override
@SuppressWarnings("unchecked")
public boolean endRead() {
set.addAll( tempList );
tempList = null;
// ensure that operationQueue is considered
return super.endRead();
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {
return set.iterator();
}
@Override
@SuppressWarnings("unchecked")
public Serializable disassemble(CollectionPersister persister) throws HibernateException {
final Serializable[] result = new Serializable[ set.size() ];
final Iterator itr = set.iterator();
int i=0;
while ( itr.hasNext() ) {
result[i++] = persister.getElementType().disassemble( itr.next(), getSession(), null );
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
final Type elementType = persister.getElementType();
final java.util.Map sn = (java.util.Map) getSnapshot();
final ArrayList deletes = new ArrayList( sn.size() );
Iterator itr = sn.keySet().iterator();
while ( itr.hasNext() ) {
final Object test = itr.next();
if ( !set.contains( test ) ) {
// the element has been removed from the set
deletes.add( test );
}
}
itr = set.iterator();
while ( itr.hasNext() ) {
final Object test = itr.next();
final Object oldValue = sn.get( test );
if ( oldValue!=null && elementType.isDirty( test, oldValue, getSession() ) ) {
// the element has changed
deletes.add( oldValue );
}
}
return deletes.iterator();
}
@Override
@SuppressWarnings("unchecked")
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final Object oldValue = ( (java.util.Map) getSnapshot() ).get( entry );
// note that it might be better to iterate the snapshot but this is safe,
// assuming the user implements equals() properly, as required by the Set
// contract!
return ( oldValue == null && entry != null ) || elemType.isDirty( oldValue, entry, getSession() );
}
@Override
@SuppressWarnings("unchecked")
public boolean needsUpdating(Object entry, int i, Type elemType) {
return false;
}
@Override
@SuppressWarnings("unchecked")
public boolean isRowUpdatePossible() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public Object getIndex(Object entry, int i, CollectionPersister persister) {
throw new UnsupportedOperationException("Sets don't have indexes");
}
@Override
@SuppressWarnings("unchecked")
public Object getElement(Object entry) {
return entry;
}
@Override
@SuppressWarnings("unchecked")
public Object getSnapshotElement(Object entry, int i) {
throw new UnsupportedOperationException("Sets don't support updating by element");
}
@Override
@SuppressWarnings({"unchecked", "EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object other) {
read();
return set.equals( other );
}
@Override
@SuppressWarnings("unchecked")
public int hashCode() {
read();
return set.hashCode();
}
@Override
@SuppressWarnings("unchecked")
public boolean entryExists(Object key, int i) {
return key != null;
}
@Override
@SuppressWarnings("unchecked")
public boolean isWrapper(Object collection) {
return set==collection;
}
final class Clear implements DelayedOperation {
@Override
public void operate() {
set.clear();
}
@Override
public Object getAddedInstance() {
return null;
}
@Override
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
}
}
final class SimpleAdd extends AbstractValueDelayedOperation {
public SimpleAdd(Object addedValue) {
super( addedValue, null );
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
set.add( getAddedInstance() );
}
}
final class SimpleRemove extends AbstractValueDelayedOperation {
public SimpleRemove(Object orphan) {
super( null, orphan );
}
@Override
@SuppressWarnings("unchecked")
public void operate() {
set.remove( getOrphan() );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy