alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (ForeignKeys.java)

This example Hibernate source code file (ForeignKeys.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

boolean, compositetype, entitytype, hibernateexception, hibernateexception, hibernateproxy, io, object, object, serializable, sessionimplementor, sessionimplementor, string, string, type

The Hibernate ForeignKeys.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.engine.internal;

import java.io.Serializable;

import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.TransientObjectException;
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;

/**
 * Algorithms related to foreign key constraint transparency
 * 
 * @author Gavin King
 */
public final class ForeignKeys {
	
	private ForeignKeys() {}
	
	public static class Nullifier {
	
		private final boolean isDelete;
		private final boolean isEarlyInsert;
		private final SessionImplementor session;
		private final Object self;
		
		public Nullifier(Object self, boolean isDelete, boolean isEarlyInsert, SessionImplementor session) {
			this.isDelete = isDelete;
			this.isEarlyInsert = isEarlyInsert;
			this.session = session;
			this.self = self;
		}
		
		/**
		 * Nullify all references to entities that have not yet 
		 * been inserted in the database, where the foreign key
		 * points toward that entity
		 */
		public void nullifyTransientReferences(final Object[] values, final Type[] types) 
		throws HibernateException {
			for ( int i = 0; i < types.length; i++ ) {
				values[i] = nullifyTransientReferences( values[i], types[i] );
			}
		}
	
		/**
		 * Return null if the argument is an "unsaved" entity (ie. 
		 * one with no existing database row), or the input argument 
		 * otherwise. This is how Hibernate avoids foreign key constraint
		 * violations.
		 */
		private Object nullifyTransientReferences(final Object value, final Type type) 
		throws HibernateException {
			if ( value == null ) {
				return null;
			}
			else if ( type.isEntityType() ) {
				EntityType entityType = (EntityType) type;
				if ( entityType.isOneToOne() ) {
					return value;
				}
				else {
					String entityName = entityType.getAssociatedEntityName();
					return isNullifiable(entityName, value) ? null : value;
				}
			}
			else if ( type.isAnyType() ) {
				return isNullifiable(null, value) ? null : value;
			}
			else if ( type.isComponentType() ) {
				CompositeType actype = (CompositeType) type;
				Object[] subvalues = actype.getPropertyValues(value, session);
				Type[] subtypes = actype.getSubtypes();
				boolean substitute = false;
				for ( int i = 0; i < subvalues.length; i++ ) {
					Object replacement = nullifyTransientReferences( subvalues[i], subtypes[i] );
					if ( replacement != subvalues[i] ) {
						substitute = true;
						subvalues[i] = replacement;
					}
				}
				if ( substitute ) {
					// todo : need to account for entity mode on the CompositeType interface :(
					actype.setPropertyValues( value, subvalues, EntityMode.POJO );
				}
				return value;
			}
			else {
				return value;
			}
		}
	
		/**
		 * Determine if the object already exists in the database, 
		 * using a "best guess"
		 */
		private boolean isNullifiable(final String entityName, Object object) 
		throws HibernateException {
			
			if (object==LazyPropertyInitializer.UNFETCHED_PROPERTY) return false; //this is kinda the best we can do...
			
			if ( object instanceof HibernateProxy ) {
				// if its an uninitialized proxy it can't be transient
				LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
				if ( li.getImplementation(session) == null ) {
					return false;
					// ie. we never have to null out a reference to
					// an uninitialized proxy
				}
				else {
					//unwrap it
					object = li.getImplementation();
				}
			}
	
			// if it was a reference to self, don't need to nullify
			// unless we are using native id generation, in which
			// case we definitely need to nullify
			if ( object == self ) {
				return isEarlyInsert || (
					isDelete &&
					session.getFactory()
						.getDialect()
						.hasSelfReferentialForeignKeyBug()
				);
			}
	
			// See if the entity is already bound to this session, if not look at the
			// entity identifier and assume that the entity is persistent if the
			// id is not "unsaved" (that is, we rely on foreign keys to keep
			// database integrity)
	
			EntityEntry entityEntry = session.getPersistenceContext().getEntry(object);
			if ( entityEntry==null ) {
				return isTransient(entityName, object, null, session);
			}
			else {
				return entityEntry.isNullifiable(isEarlyInsert, session);
			}
	
		}
		
	}
	
	/**
	 * Is this instance persistent or detached?
	 * If <tt>assumed is non-null, don't hit the database to make the 
	 * determination, instead assume that value; the client code must be 
	 * prepared to "recover" in the case that this assumed result is incorrect.
	 */
	public static boolean isNotTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) 
	throws HibernateException {
		if (entity instanceof HibernateProxy) return true;
		if ( session.getPersistenceContext().isEntryFor(entity) ) return true;
		return !isTransient(entityName, entity, assumed, session);
	}
	
	/**
	 * Is this instance, which we know is not persistent, actually transient?
	 * If <tt>assumed is non-null, don't hit the database to make the 
	 * determination, instead assume that value; the client code must be 
	 * prepared to "recover" in the case that this assumed result is incorrect.
	 */
	public static boolean isTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) 
	throws HibernateException {
		
		if (entity== LazyPropertyInitializer.UNFETCHED_PROPERTY) {
			// an unfetched association can only point to
			// an entity that already exists in the db
			return false;
		}
		
		// let the interceptor inspect the instance to decide
		Boolean isUnsaved = session.getInterceptor().isTransient(entity);
		if (isUnsaved!=null) return isUnsaved.booleanValue();
		
		// let the persister inspect the instance to decide
		EntityPersister persister = session.getEntityPersister(entityName, entity);
		isUnsaved = persister.isTransient(entity, session);
		if (isUnsaved!=null) return isUnsaved.booleanValue();

		// we use the assumed value, if there is one, to avoid hitting
		// the database
		if (assumed!=null) return assumed.booleanValue();
		
		// hit the database, after checking the session cache for a snapshot
		Object[] snapshot = session.getPersistenceContext().getDatabaseSnapshot(
				persister.getIdentifier( entity, session ),
				persister
		);
		return snapshot==null;

	}

	/**
	 * Return the identifier of the persistent or transient object, or throw
	 * an exception if the instance is "unsaved"
	 *
	 * Used by OneToOneType and ManyToOneType to determine what id value should 
	 * be used for an object that may or may not be associated with the session. 
	 * This does a "best guess" using any/all info available to use (not just the 
	 * EntityEntry).
	 */
	public static Serializable getEntityIdentifierIfNotUnsaved(
			final String entityName, 
			final Object object, 
			final SessionImplementor session)
	throws HibernateException {
		if ( object == null ) {
			return null;
		}
		else {
			Serializable id = session.getContextEntityIdentifier( object );
			if ( id == null ) {
				// context-entity-identifier returns null explicitly if the entity
				// is not associated with the persistence context; so make some
				// deeper checks...
				if ( isTransient(entityName, object, Boolean.FALSE, session) ) {
					throw new TransientObjectException(
							"object references an unsaved transient instance - save the transient instance before flushing: " +
							(entityName == null ? session.guessEntityName( object ) : entityName)
					);
				}
				id = session.getEntityPersister( entityName, object ).getIdentifier( object, session );
			}
			return id;
		}
	}

}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate ForeignKeys.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.