HHH-8159 - Apply fixups indicated by analysis tools

This commit is contained in:
Steve Ebersole 2013-04-19 14:35:22 -05:00
parent bca73db4f9
commit 6a388b754c
127 changed files with 3128 additions and 1768 deletions

View File

@ -315,8 +315,14 @@ subprojects { subProject ->
task checkstylePublicSources(type: Checkstyle) {
checkstyleClasspath = checkstyleMain.checkstyleClasspath
classpath = checkstyleMain.classpath
configFile = rootProject.file( 'shared/config/checkstyle/public_checks.xml' )
configFile = rootProject.file( 'shared/config/checkstyle/checkstyle.xml' )
source subProject.sourceSets.main.originalJavaSrcDirs
// exclude generated sources
exclude '**/generated-src/**'
// because cfg package is a mess mainly from annotation stuff
exclude '**/org/hibernate/cfg/**'
exclude '**/org/hibernate/cfg/*'
// because this should only report on api/spi
exclude '**/internal/**'
exclude '**/internal/*'
ignoreFailures = false
@ -331,13 +337,21 @@ subprojects { subProject ->
// Report configs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
checkstyle {
sourceSets = [ subProject.sourceSets.main ]
configFile = rootProject.file( 'shared/config/checkstyle/checkstyle.xml' )
showViolations = false
ignoreFailures = true
}
// exclude generated sources
checkstyleMain.exclude '**/generated-src/**'
// because cfg package is a mess mainly from annotation stuff
checkstyleMain.exclude '**/org/hibernate/cfg/**'
checkstyleMain.exclude '**/org/hibernate/cfg/*'
findbugs {
ignoreFailures = true
}
buildDashboard.dependsOn check
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -33,19 +33,22 @@ import org.hibernate.internal.CoreMessageLogger;
* @author Gavin King
*/
public class AssertionFailure extends RuntimeException {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, AssertionFailure.class.getName());
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
AssertionFailure.class.getName()
);
/**
* Creates an instance of AssertionFailure using the given message.
*
* @param message The message explaining the reason for the exception
*/
public AssertionFailure(String message) {
super( message );
LOG.failed( this );
}
public AssertionFailure(String message) {
super( message );
LOG.failed( this );
}
/**
* Creates an instance of AssertionFailure using the given message and underlying cause.
@ -53,8 +56,8 @@ public class AssertionFailure extends RuntimeException {
* @param message The message explaining the reason for the exception
* @param cause The underlying cause.
*/
public AssertionFailure(String message, Throwable cause) {
super( message, cause );
LOG.failed( cause );
}
public AssertionFailure(String message, Throwable cause) {
super( message, cause );
LOG.failed( cause );
}
}

View File

@ -60,7 +60,7 @@ public enum ConnectionReleaseMode{
*
* @return The matched enum value.
*/
public static ConnectionReleaseMode parse(final String name){
public static ConnectionReleaseMode parse(final String name) {
return ConnectionReleaseMode.valueOf( name.toUpperCase() );
}
}

View File

@ -119,7 +119,7 @@ public interface Criteria extends CriteriaSpecification {
* @return this (for method chaining)
*/
public Criteria add(Criterion criterion);
/**
* Add an {@link Order ordering} to the result set.
*
@ -393,7 +393,7 @@ public interface Criteria extends CriteriaSpecification {
* @return this (for method chaining)
*/
public Criteria setMaxResults(int maxResults);
/**
* Set the first result to be retrieved.
*
@ -531,7 +531,7 @@ public interface Criteria extends CriteriaSpecification {
* exeucting the SQL or processing the SQL results.
*/
public List list() throws HibernateException;
/**
* Get the results as an instance of {@link ScrollableResults}.
*

View File

@ -28,16 +28,23 @@ package org.hibernate;
*
* @author Steve Ebersole
*/
public abstract class HibernateError extends HibernateException {
public class HibernateError extends HibernateException {
/**
* Constructs HibernateError with the condition message.
*
* @param message Message explaining the exception/error condition
*/
public HibernateError(String message) {
super( message );
}
public HibernateError(Throwable root) {
super( root );
}
public HibernateError(String message, Throwable root) {
super( message, root );
/**
* Constructs HibernateError with the condition message and cause.
*
* @param message Message explaining the exception/error condition
* @param cause The underlying cause.
*/
public HibernateError(String message, Throwable cause) {
super( message, cause );
}
}

View File

@ -61,7 +61,7 @@ public class InvalidMappingException extends MappingException {
* @param path The path (type specific) of the invalid mapping document
*/
public InvalidMappingException(String customMessage, String type, String path) {
super(customMessage);
super( customMessage );
this.type=type;
this.path=path;
}
@ -104,7 +104,7 @@ public class InvalidMappingException extends MappingException {
* @param path The path (type specific) of the invalid mapping document
*/
public InvalidMappingException(String type, String path) {
this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path);
this( "Could not parse mapping document from " + type + (path==null?"":" " + path), type, path );
}
/**
@ -115,7 +115,7 @@ public class InvalidMappingException extends MappingException {
* @param cause The underlying cause
*/
public InvalidMappingException(String type, String path, Throwable cause) {
this("Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause);
this( "Could not parse mapping document from " + type + (path==null?"":" " + path), type, path, cause );
}
/**

View File

@ -57,7 +57,7 @@ public enum LockMode {
*
* @deprecated instead use PESSIMISTIC_WRITE
*/
@Deprecated
@Deprecated
UPGRADE( 10 ),
/**
* Attempt to obtain an upgrade lock, using an Oracle-style
@ -89,7 +89,7 @@ public enum LockMode {
*
* @deprecated instead use PESSIMISTIC_FORCE_INCREMENT
*/
@Deprecated
@Deprecated
FORCE( 15 ),
/**
@ -151,6 +151,4 @@ public enum LockMode {
public boolean lessThan(LockMode mode) {
return level < mode.level;
}
}

View File

@ -46,7 +46,7 @@ public class MappingException extends HibernateException {
* @param cause The underlying cause
*/
public MappingException(Throwable cause) {
super(cause);
super( cause );
}
/**
@ -55,7 +55,7 @@ public class MappingException extends HibernateException {
* @param message A message explaining the exception condition
*/
public MappingException(String message) {
super(message);
super( message );
}
}

View File

@ -41,9 +41,9 @@ public class MappingNotFoundException extends MappingException {
* @param cause The underlying cause
*/
public MappingNotFoundException(String customMessage, String type, String path, Throwable cause) {
super(customMessage, cause);
this.type=type;
this.path=path;
super( customMessage, cause );
this.type = type;
this.path = path;
}
/**
@ -54,9 +54,9 @@ public class MappingNotFoundException extends MappingException {
* @param path The path (type specific) of the mapping that could not be found
*/
public MappingNotFoundException(String customMessage, String type, String path) {
super(customMessage);
this.type=type;
this.path=path;
super( customMessage );
this.type = type;
this.path = path;
}
/**
@ -66,7 +66,7 @@ public class MappingNotFoundException extends MappingException {
* @param path The path (type specific) of the mapping that could not be found
*/
public MappingNotFoundException(String type, String path) {
this(type + ": " + path + " not found", type, path);
this( type + ": " + path + " not found", type, path );
}
/**
@ -77,7 +77,7 @@ public class MappingNotFoundException extends MappingException {
* @param cause The underlying cause
*/
public MappingNotFoundException(String type, String path, Throwable cause) {
this(type + ": " + path + " not found", type, path, cause);
this( type + ": " + path + " not found", type, path, cause );
}
public String getType() {

View File

@ -46,6 +46,6 @@ public class ObjectNotFoundException extends UnresolvableObjectException {
* @param entityName The name of the entity
*/
public ObjectNotFoundException(Serializable identifier, String entityName) {
super(identifier, entityName);
super( identifier, entityName );
}
}

View File

@ -57,7 +57,7 @@ public class PropertyAccessException extends HibernateException {
boolean wasSetter,
Class persistentClass,
String propertyName) {
super(message, cause);
super( message, cause );
this.persistentClass = persistentClass;
this.wasSetter = wasSetter;
this.propertyName = propertyName;
@ -72,15 +72,9 @@ public class PropertyAccessException extends HibernateException {
}
@Override
public String getMessage() {
return super.getMessage() +
( wasSetter ? " setter of " : " getter of ") +
StringHelper.qualify( persistentClass.getName(), propertyName );
public String getMessage() {
return super.getMessage()
+ ( wasSetter ? " setter of " : " getter of " )
+ StringHelper.qualify( persistentClass.getName(), propertyName );
}
}

View File

@ -36,6 +36,6 @@ public class PropertyNotFoundException extends MappingException {
* @param message A message explaining the exception condition
*/
public PropertyNotFoundException(String message) {
super(message);
super( message );
}
}

View File

@ -46,7 +46,7 @@ public class PropertyValueException extends HibernateException {
* @param propertyName The name of the property being accessed.
*/
public PropertyValueException(String message, String entityName, String propertyName) {
super(message);
super( message );
this.entityName = entityName;
this.propertyName = propertyName;
}
@ -60,7 +60,7 @@ public class PropertyValueException extends HibernateException {
}
@Override
public String getMessage() {
public String getMessage() {
return super.getMessage() + " : " + StringHelper.qualify( entityName, propertyName );
}
}

View File

@ -39,7 +39,7 @@ public class QueryException extends HibernateException {
* @param message A message explaining the exception condition
*/
public QueryException(String message) {
super(message);
super( message );
}
/**
@ -49,7 +49,7 @@ public class QueryException extends HibernateException {
* @param cause The underlying cause
*/
public QueryException(String message, Throwable cause) {
super(message, cause);
super( message, cause );
}
/**
@ -59,7 +59,7 @@ public class QueryException extends HibernateException {
* @param queryString The query being evaluated when the exception occurred
*/
public QueryException(String message, String queryString) {
super(message);
super( message );
this.queryString = queryString;
}
@ -69,7 +69,7 @@ public class QueryException extends HibernateException {
* @param cause The underlying cause
*/
public QueryException(Exception cause) {
super(cause);
super( cause );
}
/**

View File

@ -39,7 +39,6 @@ public class QueryTimeoutException extends JDBCException {
* @param sql The sql being executed when the exception occurred.
*/
public QueryTimeoutException(String message, SQLException sqlException, String sql) {
super(message, sqlException, sql);
super( message, sqlException, sql );
}
}

View File

@ -253,7 +253,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictEntityRegion(Class)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evict(Class persistentClass) throws HibernateException;
/**
@ -271,7 +271,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#containsEntity(Class, Serializable)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evict(Class persistentClass, Serializable id) throws HibernateException;
/**
@ -288,7 +288,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictEntityRegion(String)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictEntity(String entityName) throws HibernateException;
/**
@ -306,7 +306,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictEntity(String,Serializable)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictEntity(String entityName, Serializable id) throws HibernateException;
/**
@ -323,7 +323,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictCollectionRegion(String)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictCollection(String roleName) throws HibernateException;
/**
@ -341,7 +341,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictCollection(String,Serializable)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictCollection(String roleName, Serializable id) throws HibernateException;
/**
@ -355,7 +355,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictQueryRegion(String)} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictQueries(String cacheRegion) throws HibernateException;
/**
@ -367,7 +367,7 @@ public interface SessionFactory extends Referenceable, Serializable {
* @deprecated Use {@link Cache#evictQueryRegions} accessed through
* {@link #getCache()} instead.
*/
@Deprecated
@Deprecated
public void evictQueries() throws HibernateException;
/**

View File

@ -44,7 +44,7 @@ public class StaleObjectStateException extends StaleStateException {
* @param identifier The identifier of the entity
*/
public StaleObjectStateException(String entityName, Serializable identifier) {
super("Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)");
super( "Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)" );
this.entityName = entityName;
this.identifier = identifier;
}

View File

@ -40,6 +40,6 @@ public class StaleStateException extends HibernateException {
* @param message The message explaining the exception condition
*/
public StaleStateException(String message) {
super(message);
super( message );
}
}

View File

@ -37,7 +37,7 @@ public class TransactionException extends HibernateException {
* @param cause The underlying cause
*/
public TransactionException(String message, Throwable cause) {
super(message,cause);
super( message, cause );
}
/**
@ -46,7 +46,7 @@ public class TransactionException extends HibernateException {
* @param message The message explaining the exception condition
*/
public TransactionException(String message) {
super(message);
super( message );
}
}

View File

@ -35,7 +35,7 @@ public class TransientObjectException extends HibernateException {
* @param message The message explaining the exception condition
*/
public TransientObjectException(String message) {
super(message);
super( message );
}
}

View File

@ -50,7 +50,7 @@ public class TransientPropertyValueException extends TransientObjectException {
String transientEntityName,
String propertyOwnerEntityName,
String propertyName) {
super(message);
super( message );
this.transientEntityName = transientEntityName;
this.propertyOwnerEntityName = propertyOwnerEntityName;
this.propertyName = propertyName;

View File

@ -48,7 +48,7 @@ public class UnresolvableObjectException extends HibernateException {
}
protected UnresolvableObjectException(String message, Serializable identifier, String clazz) {
super(message);
super( message );
this.identifier = identifier;
this.entityName = clazz;
}
@ -79,8 +79,7 @@ public class UnresolvableObjectException extends HibernateException {
@Override
public String getMessage() {
return super.getMessage() + ": " +
MessageHelper.infoString(entityName, identifier);
return super.getMessage() + ": " + MessageHelper.infoString( entityName, identifier );
}
}

View File

@ -72,7 +72,7 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
this.isExecuted = false;
this.areTransientReferencesNullified = false;
if (id != null) {
if ( id != null ) {
handleNaturalIdPreSaveNotifications();
}
}
@ -139,7 +139,7 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
*/
public final void makeEntityManaged() {
nullifyTransientReferencesIfNotAlready();
Object version = Versioning.getVersion( getState(), getPersister() );
final Object version = Versioning.getVersion( getState(), getPersister() );
getSession().getPersistenceContext().addEntity(
getInstance(),
( getPersister().isMutable() ? Status.MANAGED : Status.READ_ONLY ),
@ -168,12 +168,12 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
protected abstract EntityKey getEntityKey();
@Override
public void afterDeserialize(SessionImplementor session) {
public void afterDeserialize(SessionImplementor session) {
super.afterDeserialize( session );
// IMPL NOTE: non-flushed changes code calls this method with session == null...
// guard against NullPointerException
if ( session != null ) {
EntityEntry entityEntry = session.getPersistenceContext().getEntry( getInstance() );
final EntityEntry entityEntry = session.getPersistenceContext().getEntry( getInstance() );
this.state = entityEntry.getLoadedState();
}
}
@ -194,9 +194,11 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
/**
* Handle sending notifications needed for natural-id after saving
*
* @param generatedId The generated entity identifier
*/
public void handleNaturalIdPostSaveNotifications(Serializable generatedId) {
if (isEarlyInsert()) {
if ( isEarlyInsert() ) {
// with early insert, we still need to add a local (transactional) natural id cross-reference
getSession().getPersistenceContext().getNaturalIdHelper().manageLocalNaturalIdCrossReference(
getPersister(),

View File

@ -73,8 +73,8 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
* @param affectedQueryables The affected entity persisters.
*/
public BulkOperationCleanupAction(SessionImplementor session, Queryable... affectedQueryables) {
SessionFactoryImplementor factory = session.getFactory();
LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
final SessionFactoryImplementor factory = session.getFactory();
final LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
for ( Queryable persister : affectedQueryables ) {
spacesList.addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
@ -85,10 +85,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
naturalIdCleanups.add( new NaturalIdCleanup( persister.getNaturalIdCacheAccessStrategy() ) );
}
Set<String> roles = factory.getCollectionRolesByEntityParticipant( persister.getEntityName() );
final Set<String> roles = factory.getCollectionRolesByEntityParticipant( persister.getEntityName() );
if ( roles != null ) {
for ( String role : roles ) {
CollectionPersister collectionPersister = factory.getCollectionPersister( role );
final CollectionPersister collectionPersister = factory.getCollectionPersister( role );
if ( collectionPersister.hasCache() ) {
collectionCleanups.add( new CollectionCleanup( collectionPersister.getCacheAccessStrategy() ) );
}
@ -113,10 +113,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
*/
@SuppressWarnings({ "unchecked" })
public BulkOperationCleanupAction(SessionImplementor session, Set tableSpaces) {
LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
final LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
spacesList.addAll( tableSpaces );
SessionFactoryImplementor factory = session.getFactory();
final SessionFactoryImplementor factory = session.getFactory();
for ( String entityName : factory.getAllClassMetadata().keySet() ) {
final EntityPersister persister = factory.getEntityPersister( entityName );
final String[] entitySpaces = (String[]) persister.getQuerySpaces();
@ -130,10 +130,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
naturalIdCleanups.add( new NaturalIdCleanup( persister.getNaturalIdCacheAccessStrategy() ) );
}
Set<String> roles = session.getFactory().getCollectionRolesByEntityParticipant( persister.getEntityName() );
final Set<String> roles = session.getFactory().getCollectionRolesByEntityParticipant( persister.getEntityName() );
if ( roles != null ) {
for ( String role : roles ) {
CollectionPersister collectionPersister = factory.getCollectionPersister( role );
final CollectionPersister collectionPersister = factory.getCollectionPersister( role );
if ( collectionPersister.hasCache() ) {
collectionCleanups.add(
new CollectionCleanup( collectionPersister.getCacheAccessStrategy() )

View File

@ -54,8 +54,8 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
private final Serializable key;
private final String collectionRole;
public CollectionAction(
final CollectionPersister persister,
protected CollectionAction(
final CollectionPersister persister,
final PersistentCollection collection,
final Serializable key,
final SessionImplementor session) {
@ -144,7 +144,7 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
protected final void evict() throws CacheException {
if ( persister.hasCache() ) {
CacheKey ck = session.generateCacheKey(
final CacheKey ck = session.generateCacheKey(
key,
persister.getKeyType(),
persister.getRole()
@ -155,22 +155,21 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
@Override
public String toString() {
return StringHelper.unqualify( getClass().getName() ) +
MessageHelper.infoString( collectionRole, key );
return StringHelper.unqualify( getClass().getName() ) + MessageHelper.infoString( collectionRole, key );
}
@Override
public int compareTo(Object other) {
CollectionAction action = ( CollectionAction ) other;
//sort first by role name
int roleComparison = collectionRole.compareTo( action.collectionRole );
final CollectionAction action = (CollectionAction) other;
// sort first by role name
final int roleComparison = collectionRole.compareTo( action.collectionRole );
if ( roleComparison != 0 ) {
return roleComparison;
}
else {
//then by fk
return persister.getKeyType()
.compare( key, action.key );
return persister.getKeyType().compare( key, action.key );
}
}

View File

@ -26,7 +26,6 @@ package org.hibernate.action.internal;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
@ -37,13 +36,24 @@ import org.hibernate.event.spi.PreCollectionRecreateEvent;
import org.hibernate.event.spi.PreCollectionRecreateEventListener;
import org.hibernate.persister.collection.CollectionPersister;
/**
* The action for recreating a collection
*/
public final class CollectionRecreateAction extends CollectionAction {
/**
* Constructs a CollectionRecreateAction
*
* @param collection The collection being recreated
* @param persister The collection persister
* @param id The collection key
* @param session The session
*/
public CollectionRecreateAction(
final PersistentCollection collection,
final CollectionPersister persister,
final Serializable id,
final SessionImplementor session) throws CacheException {
final SessionImplementor session) {
super( persister, collection, id, session );
}
@ -54,25 +64,18 @@ public final class CollectionRecreateAction extends CollectionAction {
final PersistentCollection collection = getCollection();
preRecreate();
getPersister().recreate( collection, getKey(), getSession() );
getSession().getPersistenceContext()
.getCollectionEntry(collection)
.afterAction(collection);
getSession().getPersistenceContext().getCollectionEntry( collection ).afterAction( collection );
evict();
postRecreate();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
getSession().getFactory().getStatisticsImplementor()
.recreateCollection( getPersister().getRole() );
getSession().getFactory().getStatisticsImplementor().recreateCollection( getPersister().getRole() );
}
}
private void preRecreate() {
EventListenerGroup<PreCollectionRecreateEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_RECREATE );
final EventListenerGroup<PreCollectionRecreateEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_RECREATE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -83,7 +86,7 @@ public final class CollectionRecreateAction extends CollectionAction {
}
private void postRecreate() {
EventListenerGroup<PostCollectionRecreateEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_RECREATE );
final EventListenerGroup<PostCollectionRecreateEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_RECREATE );
if ( listenerGroup.isEmpty() ) {
return;
}

View File

@ -37,11 +37,13 @@ import org.hibernate.event.spi.PreCollectionRemoveEvent;
import org.hibernate.event.spi.PreCollectionRemoveEventListener;
import org.hibernate.persister.collection.CollectionPersister;
/**
* The action for removing a collection
*/
public final class CollectionRemoveAction extends CollectionAction {
private boolean emptySnapshot;
private final Object affectedOwner;
private boolean emptySnapshot;
/**
* Removes a persistent collection from its loaded owner.
*
@ -62,7 +64,7 @@ public final class CollectionRemoveAction extends CollectionAction {
final boolean emptySnapshot,
final SessionImplementor session) {
super( persister, collection, id, session );
if (collection == null) {
if ( collection == null ) {
throw new AssertionFailure("collection == null");
}
this.emptySnapshot = emptySnapshot;
@ -92,7 +94,7 @@ public final class CollectionRemoveAction extends CollectionAction {
final boolean emptySnapshot,
final SessionImplementor session) {
super( persister, null, id, session );
if (affectedOwner == null) {
if ( affectedOwner == null ) {
throw new AssertionFailure("affectedOwner == null");
}
this.emptySnapshot = emptySnapshot;
@ -112,24 +114,20 @@ public final class CollectionRemoveAction extends CollectionAction {
}
final PersistentCollection collection = getCollection();
if (collection!=null) {
getSession().getPersistenceContext()
.getCollectionEntry(collection)
.afterAction(collection);
if ( collection != null ) {
getSession().getPersistenceContext().getCollectionEntry( collection ).afterAction( collection );
}
evict();
postRemove();
evict();
postRemove();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
getSession().getFactory().getStatisticsImplementor()
.removeCollection( getPersister().getRole() );
getSession().getFactory().getStatisticsImplementor().removeCollection( getPersister().getRole() );
}
}
private void preRemove() {
EventListenerGroup<PreCollectionRemoveEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_REMOVE );
final EventListenerGroup<PreCollectionRemoveEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_REMOVE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -145,7 +143,7 @@ public final class CollectionRemoveAction extends CollectionAction {
}
private void postRemove() {
EventListenerGroup<PostCollectionRemoveEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_REMOVE );
final EventListenerGroup<PostCollectionRemoveEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_REMOVE );
if ( listenerGroup.isEmpty() ) {
return;
}

View File

@ -38,10 +38,21 @@ import org.hibernate.event.spi.PreCollectionUpdateEventListener;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
/**
* The action for updating a collection
*/
public final class CollectionUpdateAction extends CollectionAction {
private final boolean emptySnapshot;
/**
* Constructs a CollectionUpdateAction
*
* @param collection The collection to update
* @param persister The collection persister
* @param id The collection key
* @param emptySnapshot Indicates if the snapshot is empty
* @param session The session
*/
public CollectionUpdateAction(
final PersistentCollection collection,
final CollectionPersister persister,
@ -58,26 +69,31 @@ public final class CollectionUpdateAction extends CollectionAction {
final SessionImplementor session = getSession();
final CollectionPersister persister = getPersister();
final PersistentCollection collection = getCollection();
boolean affectedByFilters = persister.isAffectedByEnabledFilters(session);
final boolean affectedByFilters = persister.isAffectedByEnabledFilters( session );
preUpdate();
if ( !collection.wasInitialized() ) {
if ( !collection.hasQueuedOperations() ) throw new AssertionFailure( "no queued adds" );
if ( !collection.hasQueuedOperations() ) {
throw new AssertionFailure( "no queued adds" );
}
//do nothing - we only need to notify the cache...
}
else if ( !affectedByFilters && collection.empty() ) {
if ( !emptySnapshot ) persister.remove( id, session );
if ( !emptySnapshot ) {
persister.remove( id, session );
}
}
else if ( collection.needsRecreate(persister) ) {
if (affectedByFilters) {
else if ( collection.needsRecreate( persister ) ) {
if ( affectedByFilters ) {
throw new HibernateException(
"cannot recreate collection while filter is enabled: " +
MessageHelper.collectionInfoString(persister, collection,
id, session )
"cannot recreate collection while filter is enabled: " +
MessageHelper.collectionInfoString( persister, collection, id, session )
);
}
if ( !emptySnapshot ) persister.remove( id, session );
if ( !emptySnapshot ) {
persister.remove( id, session );
}
persister.recreate( collection, id, session );
}
else {
@ -86,22 +102,17 @@ public final class CollectionUpdateAction extends CollectionAction {
persister.insertRows( collection, id, session );
}
getSession().getPersistenceContext()
.getCollectionEntry(collection)
.afterAction(collection);
getSession().getPersistenceContext().getCollectionEntry( collection ).afterAction( collection );
evict();
postUpdate();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
getSession().getFactory().getStatisticsImplementor().
updateCollection( getPersister().getRole() );
getSession().getFactory().getStatisticsImplementor().updateCollection( getPersister().getRole() );
}
}
private void preUpdate() {
EventListenerGroup<PreCollectionUpdateEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_UPDATE );
final EventListenerGroup<PreCollectionUpdateEventListener> listenerGroup = listenerGroup( EventType.PRE_COLLECTION_UPDATE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -116,7 +127,7 @@ public final class CollectionUpdateAction extends CollectionAction {
}
private void postUpdate() {
EventListenerGroup<PostCollectionUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_UPDATE );
final EventListenerGroup<PostCollectionUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_COLLECTION_UPDATE );
if ( listenerGroup.isEmpty() ) {
return;
}

View File

@ -38,15 +38,19 @@ import java.io.Serializable;
* @author Steve Ebersole
*/
public class DelayedPostInsertIdentifier implements Serializable {
private static long SEQUENCE = 0;
private final long sequence;
private static long sequence;
private final long identifier;
/**
* Constructs a DelayedPostInsertIdentifier
*/
public DelayedPostInsertIdentifier() {
synchronized( DelayedPostInsertIdentifier.class ) {
if ( SEQUENCE == Long.MAX_VALUE ) {
SEQUENCE = 0;
if ( sequence == Long.MAX_VALUE ) {
sequence = 0;
}
this.sequence = SEQUENCE++;
this.identifier = sequence++;
}
}
@ -58,18 +62,18 @@ public class DelayedPostInsertIdentifier implements Serializable {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final DelayedPostInsertIdentifier that = ( DelayedPostInsertIdentifier ) o;
return sequence == that.sequence;
final DelayedPostInsertIdentifier that = (DelayedPostInsertIdentifier) o;
return identifier == that.identifier;
}
@Override
public int hashCode() {
return ( int ) ( sequence ^ ( sequence >>> 32 ) );
return (int) ( identifier ^ ( identifier >>> 32 ) );
}
@Override
public String toString() {
return "<delayed:" + sequence + ">";
return "<delayed:" + identifier + ">";
}
}

View File

@ -84,7 +84,7 @@ public abstract class EntityAction
protected abstract boolean hasPostCommitEventListeners();
public boolean needsAfterTransactionCompletion() {
protected boolean needsAfterTransactionCompletion() {
return persister.hasCache() || hasPostCommitEventListeners();
}
@ -104,16 +104,16 @@ public abstract class EntityAction
*/
public final Serializable getId() {
if ( id instanceof DelayedPostInsertIdentifier ) {
Serializable eeId = session.getPersistenceContext().getEntry( instance ).getId();
final Serializable eeId = session.getPersistenceContext().getEntry( instance ).getId();
return eeId instanceof DelayedPostInsertIdentifier ? null : eeId;
}
return id;
}
public final DelayedPostInsertIdentifier getDelayedId() {
return DelayedPostInsertIdentifier.class.isInstance( id ) ?
DelayedPostInsertIdentifier.class.cast( id ) :
null;
return DelayedPostInsertIdentifier.class.isInstance( id )
? DelayedPostInsertIdentifier.class.cast( id )
: null;
}
/**
@ -160,9 +160,9 @@ public abstract class EntityAction
@Override
public int compareTo(Object other) {
EntityAction action = ( EntityAction ) other;
final EntityAction action = (EntityAction) other;
//sort first by entity name
int roleComparison = entityName.compareTo( action.entityName );
final int roleComparison = entityName.compareTo( action.entityName );
if ( roleComparison != 0 ) {
return roleComparison;
}

View File

@ -29,7 +29,6 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.CacheKey;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
@ -37,11 +36,13 @@ import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostDeleteEvent;
import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.persister.entity.EntityPersister;
/**
* The action for performing an entity deletion.
*/
public final class EntityDeleteAction extends EntityAction {
private final Object version;
private final boolean isCascadeDeleteEnabled;
@ -50,14 +51,25 @@ public final class EntityDeleteAction extends EntityAction {
private SoftLock lock;
private Object[] naturalIdValues;
/**
* Constructs an EntityDeleteAction.
*
* @param id The entity identifier
* @param state The current (extracted) entity state
* @param version The current entity version
* @param instance The entity instance
* @param persister The entity persister
* @param isCascadeDeleteEnabled Whether cascade delete is enabled
* @param session The session
*/
public EntityDeleteAction(
final Serializable id,
final Object[] state,
final Object version,
final Object instance,
final EntityPersister persister,
final boolean isCascadeDeleteEnabled,
final SessionImplementor session) {
final Object[] state,
final Object version,
final Object instance,
final EntityPersister persister,
final boolean isCascadeDeleteEnabled,
final SessionImplementor session) {
super( session, id, instance, persister );
this.version = version;
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
@ -73,12 +85,12 @@ public final class EntityDeleteAction extends EntityAction {
@Override
public void execute() throws HibernateException {
Serializable id = getId();
EntityPersister persister = getPersister();
SessionImplementor session = getSession();
Object instance = getInstance();
final Serializable id = getId();
final EntityPersister persister = getPersister();
final SessionImplementor session = getSession();
final Object instance = getInstance();
boolean veto = preDelete();
final boolean veto = preDelete();
Object version = this.version;
if ( persister.isVersionPropertyGenerated() ) {
@ -106,7 +118,7 @@ public final class EntityDeleteAction extends EntityAction {
// exists on the database (needed for identity-column key generation), and
// remove it from the session cache
final PersistenceContext persistenceContext = session.getPersistenceContext();
EntityEntry entry = persistenceContext.removeEntry( instance );
final EntityEntry entry = persistenceContext.removeEntry( instance );
if ( entry == null ) {
throw new AssertionFailure( "possible nonthreadsafe access to session" );
}
@ -130,7 +142,7 @@ public final class EntityDeleteAction extends EntityAction {
private boolean preDelete() {
boolean veto = false;
EventListenerGroup<PreDeleteEventListener> listenerGroup = listenerGroup( EventType.PRE_DELETE );
final EventListenerGroup<PreDeleteEventListener> listenerGroup = listenerGroup( EventType.PRE_DELETE );
if ( listenerGroup.isEmpty() ) {
return veto;
}
@ -142,7 +154,7 @@ public final class EntityDeleteAction extends EntityAction {
}
private void postDelete() {
EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_DELETE );
final EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_DELETE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -159,7 +171,7 @@ public final class EntityDeleteAction extends EntityAction {
}
private void postCommitDelete() {
EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_DELETE );
final EventListenerGroup<PostDeleteEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_DELETE );
if ( listenerGroup.isEmpty() ) {
return;
}

View File

@ -37,21 +37,37 @@ import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.persister.entity.EntityPersister;
/**
* The action for performing entity insertions when entity is using IDENTITY column identifier generation
*
* @see EntityInsertAction
*/
public final class EntityIdentityInsertAction extends AbstractEntityInsertAction {
private final boolean isDelayed;
private final EntityKey delayedEntityKey;
private EntityKey entityKey;
//private CacheEntry cacheEntry;
private Serializable generatedId;
/**
* Constructs an EntityIdentityInsertAction
*
* @param state The current (extracted) entity state
* @param instance The entity instance
* @param persister The entity persister
* @param isVersionIncrementDisabled Whether version incrementing is disabled
* @param session The session
* @param isDelayed Are we in a situation which allows the insertion to be delayed?
*
* @throws HibernateException Indicates an illegal state
*/
public EntityIdentityInsertAction(
Object[] state,
Object instance,
EntityPersister persister,
boolean isVersionIncrementDisabled,
SessionImplementor session,
boolean isDelayed) throws HibernateException {
boolean isDelayed) {
super(
( isDelayed ? generateDelayedPostInsertIdentifier() : null ),
state,
@ -72,7 +88,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
final SessionImplementor session = getSession();
final Object instance = getInstance();
boolean veto = preInsert();
final boolean veto = preInsert();
// Don't need to lock the cache here, since if someone
// else inserted the same pk first, the insert would fail
@ -109,13 +125,13 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
}
@Override
public boolean needsAfterTransactionCompletion() {
public boolean needsAfterTransactionCompletion() {
//TODO: simply remove this override if we fix the above todos
return hasPostCommitEventListeners();
}
@Override
protected boolean hasPostCommitEventListeners() {
protected boolean hasPostCommitEventListeners() {
final EventListenerGroup<PostInsertEventListener> group = listenerGroup( EventType.POST_COMMIT_INSERT );
for ( PostInsertEventListener listener : group.listeners() ) {
if ( listener.requiresPostCommitHanding( getPersister() ) ) {
@ -141,7 +157,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
getSession().getPersistenceContext().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId );
}
EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_INSERT );
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -158,7 +174,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
}
private void postCommitInsert() {
EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT );
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -175,9 +191,10 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
}
private boolean preInsert() {
EventListenerGroup<PreInsertEventListener> listenerGroup = listenerGroup( EventType.PRE_INSERT );
final EventListenerGroup<PreInsertEventListener> listenerGroup = listenerGroup( EventType.PRE_INSERT );
if ( listenerGroup.isEmpty() ) {
return false; // NO_VETO
// NO_VETO
return false;
}
boolean veto = false;
final PreInsertEvent event = new PreInsertEvent( getInstance(), null, getState(), getPersister(), eventSource() );
@ -187,11 +204,24 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
return veto;
}
/**
* Access to the generated identifier
*
* @return The generated identifier
*/
public final Serializable getGeneratedId() {
return generatedId;
}
// TODO: nothing seems to use this method; can it be renmoved?
/**
* Access to the delayed entity key
*
* @return The delayed entity key
*
* @deprecated No Hibernate code currently uses this method
*/
@Deprecated
@SuppressWarnings("UnusedDeclaration")
public EntityKey getDelayedEntityKey() {
return delayedEntityKey;
}
@ -206,7 +236,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction
return entityKey != null ? entityKey : delayedEntityKey;
}
private synchronized static DelayedPostInsertIdentifier generateDelayedPostInsertIdentifier() {
private static synchronized DelayedPostInsertIdentifier generateDelayedPostInsertIdentifier() {
return new DelayedPostInsertIdentifier();
}

View File

@ -29,7 +29,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
* Verify/Increment the entity version
* A BeforeTransactionCompletionProcess impl to verify and increment an entity version as party
* of before-transaction-completion processing
*
* @author Scott Marlow
*/
@ -37,6 +38,12 @@ public class EntityIncrementVersionProcess implements BeforeTransactionCompletio
private final Object object;
private final EntityEntry entry;
/**
* Constructs an EntityIncrementVersionProcess for the given entity.
*
* @param object The entity instance
* @param entry The entity's EntityEntry reference
*/
public EntityIncrementVersionProcess(Object object, EntityEntry entry) {
this.object = object;
this.entry = entry;
@ -50,9 +57,7 @@ public class EntityIncrementVersionProcess implements BeforeTransactionCompletio
@Override
public void doBeforeTransactionCompletion(SessionImplementor session) {
final EntityPersister persister = entry.getPersister();
Object nextVersion = persister.forceVersionIncrement(
entry.getId(), entry.getVersion(), session
);
final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
entry.forceLocked( object, nextVersion );
}
}

View File

@ -42,11 +42,27 @@ import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.persister.entity.EntityPersister;
/**
* The action for performing an entity insertion, for entities not defined to use IDENTITY generation.
*
* @see EntityIdentityInsertAction
*/
public final class EntityInsertAction extends AbstractEntityInsertAction {
private Object version;
private Object cacheEntry;
/**
* Constructs an EntityInsertAction.
*
* @param id The entity identifier
* @param state The current (extracted) entity state
* @param instance The entity instance
* @param version The current entity version value
* @param persister The entity's persister
* @param isVersionIncrementDisabled Whether version incrementing is disabled.
* @param session The session
*/
public EntityInsertAction(
Serializable id,
Object[] state,
@ -54,7 +70,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
Object version,
EntityPersister persister,
boolean isVersionIncrementDisabled,
SessionImplementor session) throws HibernateException {
SessionImplementor session) {
super( id, state, instance, isVersionIncrementDisabled, persister, session );
this.version = version;
}
@ -73,12 +89,12 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
public void execute() throws HibernateException {
nullifyTransientReferencesIfNotAlready();
EntityPersister persister = getPersister();
SessionImplementor session = getSession();
Object instance = getInstance();
Serializable id = getId();
final EntityPersister persister = getPersister();
final SessionImplementor session = getSession();
final Object instance = getInstance();
final Serializable id = getId();
boolean veto = preInsert();
final boolean veto = preInsert();
// Don't need to lock the cache here, since if someone
// else inserted the same pk first, the insert would fail
@ -86,8 +102,8 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
if ( !veto ) {
persister.insert( id, getState(), instance, session );
EntityEntry entry = session.getPersistenceContext().getEntry( instance );
final EntityEntry entry = session.getPersistenceContext().getEntry( instance );
if ( entry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to session" );
}
@ -99,7 +115,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
if ( persister.isVersionPropertyGenerated() ) {
version = Versioning.getVersion( getState(), persister );
}
entry.postUpdate(instance, getState(), version);
entry.postUpdate( instance, getState(), version );
}
getSession().getPersistenceContext().registerInsertedKey( getPersister(), getId() );
@ -108,7 +124,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
final SessionFactoryImplementor factory = getSession().getFactory();
if ( isCachePutEnabled( persister, session ) ) {
CacheEntry ce = persister.buildCacheEntry(
final CacheEntry ce = persister.buildCacheEntry(
instance,
getState(),
version,
@ -116,14 +132,14 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
);
cacheEntry = persister.getCacheEntryStructure().structure(ce);
final CacheKey ck = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version );
final boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
}
}
handleNaturalIdPostSaveNotifications(id);
handleNaturalIdPostSaveNotifications( id );
postInsert();
@ -136,7 +152,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
}
private void postInsert() {
EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_INSERT );
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -153,7 +169,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
}
private void postCommitInsert() {
EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT );
final EventListenerGroup<PostInsertEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -172,7 +188,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
private boolean preInsert() {
boolean veto = false;
EventListenerGroup<PreInsertEventListener> listenerGroup = listenerGroup( EventType.PRE_INSERT );
final EventListenerGroup<PreInsertEventListener> listenerGroup = listenerGroup( EventType.PRE_INSERT );
if ( listenerGroup.isEmpty() ) {
return veto;
}
@ -185,10 +201,10 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws HibernateException {
EntityPersister persister = getPersister();
final EntityPersister persister = getPersister();
if ( success && isCachePutEnabled( persister, getSession() ) ) {
final CacheKey ck = getSession().generateCacheKey( getId(), persister.getIdentifierType(), persister.getRootEntityName() );
boolean put = persister.getCacheAccessStrategy().afterInsert( ck, cacheEntry, version );
final boolean put = persister.getCacheAccessStrategy().afterInsert( ck, cacheEntry, version );
if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
getSession().getFactory().getStatisticsImplementor()

View File

@ -46,6 +46,9 @@ import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.TypeHelper;
/**
* The action for performing entity updates.
*/
public final class EntityUpdateAction extends EntityAction {
private final Object[] state;
private final Object[] previousState;
@ -58,18 +61,33 @@ public final class EntityUpdateAction extends EntityAction {
private Object cacheEntry;
private SoftLock lock;
/**
* Constructs an EntityUpdateAction
*
* @param id The entity identifier
* @param state The current (extracted) entity state
* @param dirtyProperties The indexes (in reference to state) properties with dirty state
* @param hasDirtyCollection Were any collections dirty?
* @param previousState The previous (stored) state
* @param previousVersion The previous (stored) version
* @param nextVersion The incremented version
* @param instance The entity instance
* @param rowId The entity's rowid
* @param persister The entity's persister
* @param session The session
*/
public EntityUpdateAction(
final Serializable id,
final Object[] state,
final int[] dirtyProperties,
final boolean hasDirtyCollection,
final Object[] previousState,
final Object previousVersion,
final Object nextVersion,
final Object instance,
final Object rowId,
final EntityPersister persister,
final SessionImplementor session) throws HibernateException {
final Serializable id,
final Object[] state,
final int[] dirtyProperties,
final boolean hasDirtyCollection,
final Object[] previousState,
final Object previousVersion,
final Object nextVersion,
final Object instance,
final Object rowId,
final EntityPersister persister,
final SessionImplementor session) {
super( session, id, instance, persister );
this.state = state;
this.previousState = previousState;
@ -107,12 +125,12 @@ public final class EntityUpdateAction extends EntityAction {
@Override
public void execute() throws HibernateException {
Serializable id = getId();
EntityPersister persister = getPersister();
SessionImplementor session = getSession();
Object instance = getInstance();
final Serializable id = getId();
final EntityPersister persister = getPersister();
final SessionImplementor session = getSession();
final Object instance = getInstance();
boolean veto = preUpdate();
final boolean veto = preUpdate();
final SessionFactoryImplementor factory = getSession().getFactory();
Object previousVersion = this.previousVersion;
@ -150,7 +168,7 @@ public final class EntityUpdateAction extends EntityAction {
);
}
EntityEntry entry = getSession().getPersistenceContext().getEntry( instance );
final EntityEntry entry = getSession().getPersistenceContext().getEntry( instance );
if ( entry == null ) {
throw new AssertionFailure( "possible nonthreadsafe access to session" );
}
@ -185,9 +203,9 @@ public final class EntityUpdateAction extends EntityAction {
}
else {
//TODO: inefficient if that cache is just going to ignore the updated state!
CacheEntry ce = persister.buildCacheEntry( instance,state, nextVersion, getSession() );
final CacheEntry ce = persister.buildCacheEntry( instance,state, nextVersion, getSession() );
cacheEntry = persister.getCacheEntryStructure().structure( ce );
boolean put = persister.getCacheAccessStrategy().update( ck, cacheEntry, nextVersion, previousVersion );
final boolean put = persister.getCacheAccessStrategy().update( ck, cacheEntry, nextVersion, previousVersion );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );
}
@ -205,14 +223,13 @@ public final class EntityUpdateAction extends EntityAction {
postUpdate();
if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
factory.getStatisticsImplementor()
.updateEntity( getPersister().getEntityName() );
factory.getStatisticsImplementor().updateEntity( getPersister().getEntityName() );
}
}
private boolean preUpdate() {
boolean veto = false;
EventListenerGroup<PreUpdateEventListener> listenerGroup = listenerGroup( EventType.PRE_UPDATE );
final EventListenerGroup<PreUpdateEventListener> listenerGroup = listenerGroup( EventType.PRE_UPDATE );
if ( listenerGroup.isEmpty() ) {
return veto;
}
@ -231,7 +248,7 @@ public final class EntityUpdateAction extends EntityAction {
}
private void postUpdate() {
EventListenerGroup<PostUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_UPDATE );
final EventListenerGroup<PostUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_UPDATE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -250,7 +267,7 @@ public final class EntityUpdateAction extends EntityAction {
}
private void postCommitUpdate() {
EventListenerGroup<PostUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_UPDATE );
final EventListenerGroup<PostUpdateEventListener> listenerGroup = listenerGroup( EventType.POST_COMMIT_UPDATE );
if ( listenerGroup.isEmpty() ) {
return;
}
@ -282,17 +299,17 @@ public final class EntityUpdateAction extends EntityAction {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws CacheException {
EntityPersister persister = getPersister();
final EntityPersister persister = getPersister();
if ( persister.hasCache() ) {
final CacheKey ck = getSession().generateCacheKey(
getId(),
getId(),
persister.getIdentifierType(),
persister.getRootEntityName()
);
);
if ( success && cacheEntry!=null /*!persister.isCacheInvalidationRequired()*/ ) {
boolean put = persister.getCacheAccessStrategy().afterUpdate( ck, cacheEntry, nextVersion, previousVersion, lock );
final boolean put = persister.getCacheAccessStrategy().afterUpdate( ck, cacheEntry, nextVersion, previousVersion, lock );
if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
getSession().getFactory().getStatisticsImplementor().secondLevelCachePut( getPersister().getCacheAccessStrategy().getRegion().getName() );

View File

@ -31,15 +31,21 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
/**
* Verify/Increment the entity version
* A BeforeTransactionCompletionProcess impl to verify an entity version as part of
* before-transaction-completion processing
*
* @author Scott Marlow
*/
public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess {
@SuppressWarnings( {"FieldCanBeLocal", "UnusedDeclaration"})
private final Object object;
private final EntityEntry entry;
/**
* Constructs an EntityVerifyVersionProcess
*
* @param object The entity instance
* @param entry The entity's referenced EntityEntry
*/
public EntityVerifyVersionProcess(Object object, EntityEntry entry) {
this.object = object;
this.entry = entry;
@ -49,7 +55,7 @@ public class EntityVerifyVersionProcess implements BeforeTransactionCompletionPr
public void doBeforeTransactionCompletion(SessionImplementor session) {
final EntityPersister persister = entry.getPersister();
Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
final Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
if ( !entry.getVersion().equals( latestVersion ) ) {
throw new OptimisticLockException(
object,
@ -59,4 +65,4 @@ public class EntityVerifyVersionProcess implements BeforeTransactionCompletionPr
);
}
}
}
}

View File

@ -62,7 +62,8 @@ public class UnresolvedEntityInsertActions {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
UnresolvedEntityInsertActions.class.getName()
);
);
private static final int INIT_SIZE = 5;
private final Map<AbstractEntityInsertAction,NonNullableTransientDependencies> dependenciesByAction =
@ -121,17 +122,18 @@ public class UnresolvedEntityInsertActions {
LOG.trace( "No entity insert actions have non-nullable, transient entity dependencies." );
}
else {
AbstractEntityInsertAction firstDependentAction =
final AbstractEntityInsertAction firstDependentAction =
dependenciesByAction.keySet().iterator().next();
logCannotResolveNonNullableTransientDependencies( firstDependentAction.getSession() );
NonNullableTransientDependencies nonNullableTransientDependencies =
final NonNullableTransientDependencies nonNullableTransientDependencies =
dependenciesByAction.get( firstDependentAction );
Object firstTransientDependency =
final Object firstTransientDependency =
nonNullableTransientDependencies.getNonNullableTransientEntities().iterator().next();
String firstPropertyPath =
final String firstPropertyPath =
nonNullableTransientDependencies.getNonNullableTransientPropertyPaths( firstTransientDependency ).iterator().next();
throw new TransientPropertyValueException(
"Not-null property references a transient value - transient instance must be saved before current operation",
firstDependentAction.getSession().guessEntityName( firstTransientDependency ),
@ -143,23 +145,20 @@ public class UnresolvedEntityInsertActions {
private void logCannotResolveNonNullableTransientDependencies(SessionImplementor session) {
for ( Map.Entry<Object,Set<AbstractEntityInsertAction>> entry : dependentActionsByTransientEntity.entrySet() ) {
Object transientEntity = entry.getKey();
String transientEntityName = session.guessEntityName( transientEntity );
Serializable transientEntityId = session.getFactory().getEntityPersister( transientEntityName ).getIdentifier( transientEntity, session );
String transientEntityString = MessageHelper.infoString( transientEntityName, transientEntityId );
Set<String> dependentEntityStrings = new TreeSet<String>();
Set<String> nonNullableTransientPropertyPaths = new TreeSet<String>();
final Object transientEntity = entry.getKey();
final String transientEntityName = session.guessEntityName( transientEntity );
final Serializable transientEntityId = session.getFactory().getEntityPersister( transientEntityName ).getIdentifier( transientEntity, session );
final String transientEntityString = MessageHelper.infoString( transientEntityName, transientEntityId );
final Set<String> dependentEntityStrings = new TreeSet<String>();
final Set<String> nonNullableTransientPropertyPaths = new TreeSet<String>();
for ( AbstractEntityInsertAction dependentAction : entry.getValue() ) {
dependentEntityStrings.add( MessageHelper.infoString( dependentAction.getEntityName(), dependentAction.getId() ) );
for ( String path : dependenciesByAction.get( dependentAction ).getNonNullableTransientPropertyPaths( transientEntity ) ) {
String fullPath = new StringBuilder( dependentAction.getEntityName().length() + path.length() + 1 )
.append( dependentAction.getEntityName() )
.append( '.' )
.append( path )
.toString();
final String fullPath = dependentAction.getEntityName() + '.' + path;
nonNullableTransientPropertyPaths.add( fullPath );
}
}
LOG.cannotResolveNonNullableTransientDependencies(
transientEntityString,
dependentEntityStrings,
@ -200,7 +199,7 @@ public class UnresolvedEntityInsertActions {
*/
@SuppressWarnings({ "unchecked" })
public Set<AbstractEntityInsertAction> resolveDependentActions(Object managedEntity, SessionImplementor session) {
EntityEntry entityEntry = session.getPersistenceContext().getEntry( managedEntity );
final EntityEntry entityEntry = session.getPersistenceContext().getEntry( managedEntity );
if ( entityEntry.getStatus() != Status.MANAGED && entityEntry.getStatus() != Status.READ_ONLY ) {
throw new IllegalArgumentException( "EntityEntry did not have status MANAGED or READ_ONLY: " + entityEntry );
}
@ -208,7 +207,7 @@ public class UnresolvedEntityInsertActions {
final boolean traceEnabled = LOG.isTraceEnabled();
// Find out if there are any unresolved insertions that are waiting for the
// specified entity to be resolved.
Set<AbstractEntityInsertAction> dependentActions = dependentActionsByTransientEntity.remove( managedEntity );
final Set<AbstractEntityInsertAction> dependentActions = dependentActionsByTransientEntity.remove( managedEntity );
if ( dependentActions == null ) {
if ( traceEnabled ) {
LOG.tracev(
@ -216,9 +215,10 @@ public class UnresolvedEntityInsertActions {
MessageHelper.infoString( entityEntry.getEntityName(), entityEntry.getId() )
);
}
return Collections.emptySet(); //NOTE EARLY EXIT!
// NOTE EARLY EXIT!
return Collections.emptySet();
}
Set<AbstractEntityInsertAction> resolvedActions = new IdentitySet( );
final Set<AbstractEntityInsertAction> resolvedActions = new IdentitySet( );
if ( traceEnabled ) {
LOG.tracev(
"Unresolved inserts before resolving [{0}]: [{1}]",
@ -234,7 +234,7 @@ public class UnresolvedEntityInsertActions {
MessageHelper.infoString( entityEntry.getEntityName(), entityEntry.getId() )
);
}
NonNullableTransientDependencies dependencies = dependenciesByAction.get( dependentAction );
final NonNullableTransientDependencies dependencies = dependenciesByAction.get( dependentAction );
dependencies.resolveNonNullableTransientEntity( managedEntity );
if ( dependencies.isEmpty() ) {
if ( traceEnabled ) {
@ -269,11 +269,11 @@ public class UnresolvedEntityInsertActions {
@Override
public String toString() {
StringBuilder sb = new StringBuilder( getClass().getSimpleName() )
final StringBuilder sb = new StringBuilder( getClass().getSimpleName() )
.append( '[' );
for ( Map.Entry<AbstractEntityInsertAction,NonNullableTransientDependencies> entry : dependenciesByAction.entrySet() ) {
AbstractEntityInsertAction insert = entry.getKey();
NonNullableTransientDependencies dependencies = entry.getValue();
final AbstractEntityInsertAction insert = entry.getKey();
final NonNullableTransientDependencies dependencies = entry.getValue();
sb.append( "[insert=" )
.append( insert )
.append( " dependencies=[" )
@ -290,7 +290,7 @@ public class UnresolvedEntityInsertActions {
* @throws IOException if there is an error writing this object to the output stream.
*/
public void serialize(ObjectOutputStream oos) throws IOException {
int queueSize = dependenciesByAction.size();
final int queueSize = dependenciesByAction.size();
LOG.tracev( "Starting serialization of [{0}] unresolved insert entries", queueSize );
oos.writeInt( queueSize );
for ( AbstractEntityInsertAction unresolvedAction : dependenciesByAction.keySet() ) {
@ -312,12 +312,12 @@ public class UnresolvedEntityInsertActions {
ObjectInputStream ois,
SessionImplementor session) throws IOException, ClassNotFoundException {
UnresolvedEntityInsertActions rtn = new UnresolvedEntityInsertActions();
final UnresolvedEntityInsertActions rtn = new UnresolvedEntityInsertActions();
int queueSize = ois.readInt();
final int queueSize = ois.readInt();
LOG.tracev( "Starting deserialization of [{0}] unresolved insert entries", queueSize );
for ( int i = 0; i < queueSize; i++ ) {
AbstractEntityInsertAction unresolvedAction = ( AbstractEntityInsertAction ) ois.readObject();
final AbstractEntityInsertAction unresolvedAction = (AbstractEntityInsertAction) ois.readObject();
unresolvedAction.afterDeserialize( session );
rtn.addUnresolvedEntityInsertAction(
unresolvedAction,

View File

@ -0,0 +1,4 @@
/**
* Internals for action processing.
*/
package org.hibernate.action.internal;

View File

@ -40,7 +40,7 @@ public class QueryHints {
* @see org.hibernate.Query#setCacheMode
* @see org.hibernate.SQLQuery#setCacheMode
*/
public static final String CACHE_MODE = "org.hibernate.cacheMode";
public static final String CACHE_MODE = "org.hibernate.cacheMode";
/**
* The cache region to use.
@ -48,7 +48,7 @@ public class QueryHints {
* @see org.hibernate.Query#setCacheRegion
* @see org.hibernate.SQLQuery#setCacheRegion
*/
public static final String CACHE_REGION = "org.hibernate.cacheRegion";
public static final String CACHE_REGION = "org.hibernate.cacheRegion";
/**
* Are the query results cacheable?
@ -56,12 +56,12 @@ public class QueryHints {
* @see org.hibernate.Query#setCacheable
* @see org.hibernate.SQLQuery#setCacheable
*/
public static final String CACHEABLE = "org.hibernate.cacheable";
public static final String CACHEABLE = "org.hibernate.cacheable";
/**
* Is the query callable? Note: only valid for named native sql queries.
*/
public static final String CALLABLE = "org.hibernate.callable";
public static final String CALLABLE = "org.hibernate.callable";
/**
* Defines a comment to be applied to the SQL sent to the database.
@ -69,7 +69,7 @@ public class QueryHints {
* @see org.hibernate.Query#setComment
* @see org.hibernate.SQLQuery#setComment
*/
public static final String COMMENT = "org.hibernate.comment";
public static final String COMMENT = "org.hibernate.comment";
/**
* Defines the JDBC fetch size to use.
@ -77,7 +77,7 @@ public class QueryHints {
* @see org.hibernate.Query#setFetchSize
* @see org.hibernate.SQLQuery#setFetchSize
*/
public static final String FETCH_SIZE = "org.hibernate.fetchSize";
public static final String FETCH_SIZE = "org.hibernate.fetchSize";
/**
* The flush mode to associate with the execution of the query.
@ -86,7 +86,7 @@ public class QueryHints {
* @see org.hibernate.SQLQuery#setFlushMode
* @see org.hibernate.Session#setFlushMode
*/
public static final String FLUSH_MODE = "org.hibernate.flushMode";
public static final String FLUSH_MODE = "org.hibernate.flushMode";
/**
* Should entities returned from the query be set in read only mode?
@ -95,7 +95,7 @@ public class QueryHints {
* @see org.hibernate.SQLQuery#setReadOnly
* @see org.hibernate.Session#setReadOnly
*/
public static final String READ_ONLY = "org.hibernate.readOnly";
public static final String READ_ONLY = "org.hibernate.readOnly";
/**
* Apply a Hibernate query timeout, which is defined in <b>seconds</b>.
@ -103,11 +103,11 @@ public class QueryHints {
* @see org.hibernate.Query#setTimeout
* @see org.hibernate.SQLQuery#setTimeout
*/
public static final String TIMEOUT_HIBERNATE = "org.hibernate.timeout";
public static final String TIMEOUT_HIBERNATE = "org.hibernate.timeout";
/**
* Apply a JPA query timeout, which is defined in <b>milliseconds</b>.
*/
public static final String TIMEOUT_JPA = "javax.persistence.query.timeout";
public static final String TIMEOUT_JPA = "javax.persistence.query.timeout";
}

View File

@ -202,9 +202,9 @@ public class BootstrapServiceRegistryBuilder {
// the providedClassLoaders and the overridenClassLoader.
final Set<ClassLoader> classLoaders = new HashSet<ClassLoader>();
if ( providedClassLoaders != null ) {
classLoaders.addAll( providedClassLoaders );
}
if ( providedClassLoaders != null ) {
classLoaders.addAll( providedClassLoaders );
}
classLoaderService = new ClassLoaderServiceImpl( classLoaders );
}

View File

@ -53,14 +53,27 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
private final ClassLoader aggregatedClassLoader;
/**
* Constructs a ClassLoaderServiceImpl with standard set-up
*/
public ClassLoaderServiceImpl() {
this( ClassLoaderServiceImpl.class.getClassLoader() );
}
/**
* Constructs a ClassLoaderServiceImpl with the given ClassLoader
*
* @param classLoader The ClassLoader to use
*/
public ClassLoaderServiceImpl(ClassLoader classLoader) {
this( Collections.singletonList( classLoader ) );
}
/**
* Constructs a ClassLoaderServiceImpl with the given ClassLoader instances
*
* @param providedClassLoaders The ClassLoader instances to use
*/
public ClassLoaderServiceImpl(Collection<ClassLoader> providedClassLoaders) {
final LinkedHashSet<ClassLoader> orderedClassLoaderSet = new LinkedHashSet<ClassLoader>();
@ -91,22 +104,31 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
this.aggregatedClassLoader = new AggregatedClassLoader( orderedClassLoaderSet );
}
@SuppressWarnings({"UnusedDeclaration", "unchecked", "deprecation"})
/**
* No longer used/supported!
*
* @param configValues The config values
*
* @return The built service
*
* @deprecated No longer used/supported!
*/
@Deprecated
public static ClassLoaderServiceImpl fromConfigSettings(Map configVales) {
@SuppressWarnings({"UnusedDeclaration", "unchecked", "deprecation"})
public static ClassLoaderServiceImpl fromConfigSettings(Map configValues) {
final List<ClassLoader> providedClassLoaders = new ArrayList<ClassLoader>();
final Collection<ClassLoader> classLoaders = (Collection<ClassLoader>) configVales.get( AvailableSettings.CLASSLOADERS );
final Collection<ClassLoader> classLoaders = (Collection<ClassLoader>) configValues.get( AvailableSettings.CLASSLOADERS );
if ( classLoaders != null ) {
for ( ClassLoader classLoader : classLoaders ) {
providedClassLoaders.add( classLoader );
}
}
addIfSet( providedClassLoaders, AvailableSettings.APP_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.RESOURCES_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.HIBERNATE_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.ENVIRONMENT_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.APP_CLASSLOADER, configValues );
addIfSet( providedClassLoaders, AvailableSettings.RESOURCES_CLASSLOADER, configValues );
addIfSet( providedClassLoaders, AvailableSettings.HIBERNATE_CLASSLOADER, configValues );
addIfSet( providedClassLoaders, AvailableSettings.ENVIRONMENT_CLASSLOADER, configValues );
if ( providedClassLoaders.isEmpty() ) {
log.debugf( "Incoming config yielded no classloaders; adding standard SE ones" );
@ -244,7 +266,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
log.tracef( "trying via [ClassLoader.getResourceAsStream(\"%s\")]", name );
InputStream stream = aggregatedClassLoader.getResourceAsStream( name );
final InputStream stream = aggregatedClassLoader.getResourceAsStream( name );
if ( stream != null ) {
return stream;
}
@ -252,7 +274,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
catch ( Exception ignore ) {
}
final String stripped = name.startsWith( "/" ) ? name.substring(1) : null;
final String stripped = name.startsWith( "/" ) ? name.substring( 1 ) : null;
if ( stripped != null ) {
try {
@ -264,7 +286,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
try {
log.tracef( "trying via [ClassLoader.getResourceAsStream(\"%s\")]", stripped );
InputStream stream = aggregatedClassLoader.getResourceAsStream( stripped );
final InputStream stream = aggregatedClassLoader.getResourceAsStream( stripped );
if ( stream != null ) {
return stream;
}
@ -278,9 +300,9 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
@Override
public List<URL> locateResources(String name) {
ArrayList<URL> urls = new ArrayList<URL>();
final ArrayList<URL> urls = new ArrayList<URL>();
try {
Enumeration<URL> urlEnumeration = aggregatedClassLoader.getResources( name );
final Enumeration<URL> urlEnumeration = aggregatedClassLoader.getResources( name );
if ( urlEnumeration != null && urlEnumeration.hasMoreElements() ) {
while ( urlEnumeration.hasMoreElements() ) {
urls.add( urlEnumeration.nextElement() );
@ -308,10 +330,28 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
// completely temporary !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/**
* Hack around continued (temporary) need to sometimes set the TCCL for code we call that expects it.
*
* @param <T> The result type
*/
public static interface Work<T> {
/**
* The work to be performed with the TCCL set
*
* @return The result of the work
*/
public T perform();
}
/**
* Perform some discrete work with with the TCCL set to our aggregated ClassLoader
*
* @param work The discrete work to be done
* @param <T> The type of the work result
*
* @return The work result.
*/
public <T> T withTccl(Work<T> work) {
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();

View File

@ -0,0 +1,4 @@
/**
* The class loading service internals.
*/
package org.hibernate.boot.registry.classloading.internal;

View File

@ -42,8 +42,9 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* {@link ServiceRegistry} implementation containing specialized "bootstrap" services, specifically:<ul>
* <li>{@link ClassLoaderService}</li>
* <li>{@link IntegratorService}</li>
* <li>{@link ClassLoaderService}</li>
* <li>{@link IntegratorService}</li>
* <li>{@link StrategySelector}</li>
* </ul>
*
* IMPL NOTE : Currently implements the deprecated {@link org.hibernate.service.BootstrapServiceRegistry} contract
@ -61,10 +62,29 @@ public class BootstrapServiceRegistryImpl
private final ServiceBinding<StrategySelector> strategySelectorBinding;
private final ServiceBinding<IntegratorService> integratorServiceBinding;
/**
* Constructs a BootstrapServiceRegistryImpl.
*
* Do not use directly generally speaking. Use {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder}
* instead.
*
* @see org.hibernate.boot.registry.BootstrapServiceRegistryBuilder
*/
public BootstrapServiceRegistryImpl() {
this( new ClassLoaderServiceImpl(), NO_INTEGRATORS );
}
/**
* Constructs a BootstrapServiceRegistryImpl.
*
* Do not use directly generally speaking. Use {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder}
* instead.
*
* @param classLoaderService The ClassLoaderService to use
* @param providedIntegrators The group of explicitly provided integrators
*
* @see org.hibernate.boot.registry.BootstrapServiceRegistryBuilder
*/
public BootstrapServiceRegistryImpl(
ClassLoaderService classLoaderService,
LinkedHashSet<Integrator> providedIntegrators) {
@ -88,6 +108,19 @@ public class BootstrapServiceRegistryImpl
);
}
/**
* Constructs a BootstrapServiceRegistryImpl.
*
* Do not use directly generally speaking. Use {@link org.hibernate.boot.registry.BootstrapServiceRegistryBuilder}
* instead.
*
* @param classLoaderService The ClassLoaderService to use
* @param strategySelector The StrategySelector to use
* @param integratorService The IntegratorService to use
*
* @see org.hibernate.boot.registry.BootstrapServiceRegistryBuilder
*/
public BootstrapServiceRegistryImpl(
ClassLoaderService classLoaderService,
StrategySelector strategySelector,

View File

@ -37,13 +37,24 @@ import org.hibernate.service.spi.ServiceBinding;
import org.hibernate.service.spi.ServiceInitiator;
/**
* Hibernate implementation of the standard service registry.
* Standard Hibernate implementation of the standard service registry.
*
* @author Steve Ebersole
*/
public class StandardServiceRegistryImpl extends AbstractServiceRegistryImpl implements StandardServiceRegistry {
private final Map configurationValues;
/**
* Constructs a StandardServiceRegistryImpl. Should not be instantiated directly; use
* {@link org.hibernate.boot.registry.StandardServiceRegistryBuilder} instead
*
* @param bootstrapServiceRegistry The bootstrap service registry.
* @param serviceInitiators Any StandardServiceInitiators provided by the user to the builder
* @param providedServices Any standard services provided directly to the builder
* @param configurationValues Configuration values
*
* @see org.hibernate.boot.registry.StandardServiceRegistryBuilder
*/
@SuppressWarnings( {"unchecked"})
public StandardServiceRegistryImpl(
BootstrapServiceRegistry bootstrapServiceRegistry,

View File

@ -0,0 +1,4 @@
/**
* The internals for building service registries.
*/
package org.hibernate.boot.registry.internal;

View File

@ -0,0 +1,4 @@
/**
* Internals for building StrategySelector
*/
package org.hibernate.boot.registry.selector.internal;

View File

@ -51,17 +51,23 @@ public class JavassistInstrumenter extends AbstractInstrumenter {
private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
/**
* Constructs the Javassist-based instrumenter.
*
* @param logger Logger to use
* @param options Instrumentation options
*/
public JavassistInstrumenter(Logger logger, Options options) {
super( logger, options );
}
@Override
protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
return new CustomClassDescriptor( bytecode );
}
@Override
protected ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames) {
protected ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames) {
if ( descriptor.isInstrumented() ) {
logger.debug( "class [" + descriptor.getName() + "] already instrumented" );
return null;
@ -85,7 +91,7 @@ public class JavassistInstrumenter extends AbstractInstrumenter {
}
public boolean isInstrumented() {
String[] interfaceNames = classFile.getInterfaces();
final String[] interfaceNames = classFile.getInterfaces();
for ( String interfaceName : interfaceNames ) {
if ( FieldHandled.class.getName().equals( interfaceName ) ) {
return true;

View File

@ -0,0 +1,4 @@
/**
* Javassist support internals
*/
package org.hibernate.bytecode.buildtime.internal;

View File

@ -48,7 +48,7 @@ import org.hibernate.bytecode.spi.ClassTransformer;
public abstract class AbstractInstrumenter implements Instrumenter {
private static final int ZIP_MAGIC = 0x504B0304;
private static final int CLASS_MAGIC = 0xCAFEBABE;
protected final Logger logger;
protected final Options options;
@ -92,7 +92,7 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @param files The files.
*/
public void execute(Set<File> files) {
Set<String> classNames = new HashSet<String>();
final Set<String> classNames = new HashSet<String>();
if ( options.performExtendedInstrumentation() ) {
logger.debug( "collecting class names for extended instrumentation determination" );
@ -136,26 +136,26 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @throws Exception indicates problems accessing the file or its contents.
*/
private void collectClassNames(File file, final Set<String> classNames) throws Exception {
if ( isClassFile( file ) ) {
byte[] bytes = ByteCodeHelper.readByteCode( file );
ClassDescriptor descriptor = getClassDescriptor( bytes );
classNames.add( descriptor.getName() );
}
else if ( isJarFile( file ) ) {
ZipEntryHandler collector = new ZipEntryHandler() {
public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
if ( isClassFile( file ) ) {
final byte[] bytes = ByteCodeHelper.readByteCode( file );
final ClassDescriptor descriptor = getClassDescriptor( bytes );
classNames.add( descriptor.getName() );
}
else if ( isJarFile( file ) ) {
final ZipEntryHandler collector = new ZipEntryHandler() {
public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
if ( !entry.isDirectory() ) {
// see if the entry represents a class file
DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
final DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
if ( din.readInt() == CLASS_MAGIC ) {
classNames.add( getClassDescriptor( byteCode ).getName() );
classNames.add( getClassDescriptor( byteCode ).getName() );
}
}
}
};
ZipFileProcessor processor = new ZipFileProcessor( collector );
processor.process( file );
}
}
};
final ZipFileProcessor processor = new ZipFileProcessor( collector );
processor.process( file );
}
}
/**
@ -168,8 +168,8 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @throws IOException Indicates problem access the file.
*/
protected final boolean isClassFile(File file) throws IOException {
return checkMagic( file, CLASS_MAGIC );
}
return checkMagic( file, CLASS_MAGIC );
}
/**
* Does this file represent a zip file of some format?
@ -180,20 +180,20 @@ public abstract class AbstractInstrumenter implements Instrumenter {
*
* @throws IOException Indicates problem access the file.
*/
protected final boolean isJarFile(File file) throws IOException {
return checkMagic(file, ZIP_MAGIC);
}
protected final boolean isJarFile(File file) throws IOException {
return checkMagic( file, ZIP_MAGIC );
}
protected final boolean checkMagic(File file, long magic) throws IOException {
DataInputStream in = new DataInputStream( new FileInputStream( file ) );
try {
int m = in.readInt();
return magic == m;
}
finally {
in.close();
}
}
final DataInputStream in = new DataInputStream( new FileInputStream( file ) );
try {
final int m = in.readInt();
return magic == m;
}
finally {
in.close();
}
}
/**
* Actually process the file by applying instrumentation transformations to any classes it contains.
@ -207,17 +207,17 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @throws Exception Indicates an issue either access files or applying the transformations.
*/
protected void processFile(File file, Set<String> classNames) throws Exception {
if ( isClassFile( file ) ) {
if ( isClassFile( file ) ) {
logger.debug( "processing class file : " + file.getAbsolutePath() );
processClassFile( file, classNames );
}
else if ( isJarFile( file ) ) {
processClassFile( file, classNames );
}
else if ( isJarFile( file ) ) {
logger.debug( "processing jar file : " + file.getAbsolutePath() );
processJarFile( file, classNames );
}
else {
logger.debug( "ignoring file : " + file.getAbsolutePath() );
}
processJarFile( file, classNames );
}
else {
logger.debug( "ignoring file : " + file.getAbsolutePath() );
}
}
/**
@ -230,16 +230,16 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @throws Exception Indicates an issue either access files or applying the transformations.
*/
protected void processClassFile(File file, Set<String> classNames) throws Exception {
byte[] bytes = ByteCodeHelper.readByteCode( file );
ClassDescriptor descriptor = getClassDescriptor( bytes );
ClassTransformer transformer = getClassTransformer( descriptor, classNames );
final byte[] bytes = ByteCodeHelper.readByteCode( file );
final ClassDescriptor descriptor = getClassDescriptor( bytes );
final ClassTransformer transformer = getClassTransformer( descriptor, classNames );
if ( transformer == null ) {
logger.debug( "no trasformer for class file : " + file.getAbsolutePath() );
return;
}
logger.info( "processing class : " + descriptor.getName() + "; file = " + file.getAbsolutePath() );
byte[] transformedBytes = transformer.transform(
final byte[] transformedBytes = transformer.transform(
getClass().getClassLoader(),
descriptor.getName(),
null,
@ -247,7 +247,7 @@ public abstract class AbstractInstrumenter implements Instrumenter {
descriptor.getBytes()
);
OutputStream out = new FileOutputStream( file );
final OutputStream out = new FileOutputStream( file );
try {
out.write( transformedBytes );
out.flush();
@ -272,61 +272,62 @@ public abstract class AbstractInstrumenter implements Instrumenter {
* @throws Exception Indicates an issue either access files or applying the transformations.
*/
protected void processJarFile(final File file, final Set<String> classNames) throws Exception {
File tempFile = File.createTempFile(
file.getName(),
null,
new File( file.getAbsoluteFile().getParent() )
);
final File tempFile = File.createTempFile(
file.getName(),
null,
new File( file.getAbsoluteFile().getParent() )
);
try {
FileOutputStream fout = new FileOutputStream( tempFile, false );
try {
final FileOutputStream fout = new FileOutputStream( tempFile, false );
try {
final ZipOutputStream out = new ZipOutputStream( fout );
ZipEntryHandler transformer = new ZipEntryHandler() {
final ZipEntryHandler transformer = new ZipEntryHandler() {
public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
logger.debug( "starting zip entry : " + entry.toString() );
if ( !entry.isDirectory() ) {
// see if the entry represents a class file
DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
if ( din.readInt() == CLASS_MAGIC ) {
ClassDescriptor descriptor = getClassDescriptor( byteCode );
ClassTransformer transformer = getClassTransformer( descriptor, classNames );
if ( transformer == null ) {
logger.debug( "no transformer for zip entry : " + entry.toString() );
}
else {
logger.info( "processing class : " + descriptor.getName() + "; entry = " + file.getAbsolutePath() );
byteCode = transformer.transform(
getClass().getClassLoader(),
descriptor.getName(),
null,
null,
descriptor.getBytes()
);
}
}
else {
logger.debug( "ignoring zip entry : " + entry.toString() );
}
logger.debug( "starting zip entry : " + entry.toString() );
if ( !entry.isDirectory() ) {
// see if the entry represents a class file
final DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
if ( din.readInt() == CLASS_MAGIC ) {
final ClassDescriptor descriptor = getClassDescriptor( byteCode );
final ClassTransformer transformer = getClassTransformer( descriptor, classNames );
if ( transformer == null ) {
logger.debug( "no transformer for zip entry : " + entry.toString() );
}
ZipEntry outEntry = new ZipEntry( entry.getName() );
outEntry.setMethod( entry.getMethod() );
outEntry.setComment( entry.getComment() );
outEntry.setSize( byteCode.length );
if ( outEntry.getMethod() == ZipEntry.STORED ){
CRC32 crc = new CRC32();
crc.update( byteCode );
outEntry.setCrc( crc.getValue() );
outEntry.setCompressedSize( byteCode.length );
else {
logger.info( "processing class : " + descriptor.getName() + "; entry = " + file.getAbsolutePath() );
byteCode = transformer.transform(
getClass().getClassLoader(),
descriptor.getName(),
null,
null,
descriptor.getBytes()
);
}
out.putNextEntry( outEntry );
out.write( byteCode );
out.closeEntry();
}
else {
logger.debug( "ignoring zip entry : " + entry.toString() );
}
}
final ZipEntry outEntry = new ZipEntry( entry.getName() );
outEntry.setMethod( entry.getMethod() );
outEntry.setComment( entry.getComment() );
outEntry.setSize( byteCode.length );
if ( outEntry.getMethod() == ZipEntry.STORED ){
final CRC32 crc = new CRC32();
crc.update( byteCode );
outEntry.setCrc( crc.getValue() );
outEntry.setCompressedSize( byteCode.length );
}
out.putNextEntry( outEntry );
out.write( byteCode );
out.closeEntry();
}
};
ZipFileProcessor processor = new ZipFileProcessor( transformer );
final ZipFileProcessor processor = new ZipFileProcessor( transformer );
processor.process( file );
out.close();
}
@ -334,21 +335,21 @@ public abstract class AbstractInstrumenter implements Instrumenter {
fout.close();
}
if ( file.delete() ) {
File newFile = new File( tempFile.getAbsolutePath() );
if( !newFile.renameTo( file ) ) {
throw new IOException( "can not rename " + tempFile + " to " + file );
}
}
else {
throw new IOException( "can not delete " + file );
}
}
finally {
if ( ! tempFile.delete() ) {
if ( file.delete() ) {
final File newFile = new File( tempFile.getAbsolutePath() );
if( ! newFile.renameTo( file ) ) {
throw new IOException( "can not rename " + tempFile + " to " + file );
}
}
else {
throw new IOException( "can not delete " + file );
}
}
finally {
if ( ! tempFile.delete() ) {
logger.info( "Unable to cleanup temporary jar file : " + tempFile.getAbsolutePath() );
}
}
}
}
/**
@ -419,19 +420,19 @@ public abstract class AbstractInstrumenter implements Instrumenter {
}
public void process(File file) throws Exception {
ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
final ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
try {
ZipEntry entry;
while ( (entry = zip.getNextEntry()) != null ) {
byte bytes[] = ByteCodeHelper.readByteCode( zip );
final byte[] bytes = ByteCodeHelper.readByteCode( zip );
entryHandler.handleEntry( entry, bytes );
zip.closeEntry();
}
}
finally {
zip.close();
}
}
finally {
zip.close();
}
}
}
}

View File

@ -39,10 +39,19 @@ public class BasicClassFilter implements ClassFilter {
private final Set<String> includedClassNames = new HashSet<String>();
private final boolean isAllEmpty;
/**
* Constructs a BasicClassFilter with given configuration.
*/
public BasicClassFilter() {
this( null, null );
}
/**
* Constructs a BasicClassFilter with standard set of configuration.
*
* @param includedPackages Name of packages whose classes should be accepted.
* @param includedClassNames Name of classes that should be accepted.
*/
public BasicClassFilter(String[] includedPackages, String[] includedClassNames) {
this.includedPackages = includedPackages;
if ( includedClassNames != null ) {
@ -50,9 +59,10 @@ public class BasicClassFilter implements ClassFilter {
}
isAllEmpty = ( this.includedPackages == null || this.includedPackages.length == 0 )
&& ( this.includedClassNames.isEmpty() );
&& ( this.includedClassNames.isEmpty() );
}
@Override
public boolean shouldInstrumentClass(String className) {
return isAllEmpty ||
includedClassNames.contains( className ) ||

View File

@ -30,7 +30,7 @@ package org.hibernate.bytecode.buildtime.spi;
*/
public interface ClassFilter {
/**
* Should this class be included in instrumentation
* Should this class be included in instrumentation.
*
* @param className The name of the class to check
*

View File

@ -30,14 +30,30 @@ package org.hibernate.bytecode.buildtime.spi;
*/
@SuppressWarnings( {"UnusedDeclaration"})
public class ExecutionException extends RuntimeException {
/**
* Constructs an ExecutionException.
*
* @param message The message explaining the exception condition
*/
public ExecutionException(String message) {
super( message );
}
/**
* Constructs an ExecutionException.
*
* @param cause The underlying cause.
*/
public ExecutionException(Throwable cause) {
super( cause );
}
/**
* Constructs an ExecutionException.
*
* @param message The message explaining the exception condition
* @param cause The underlying cause.
*/
public ExecutionException(String message, Throwable cause) {
super( message, cause );
}

View File

@ -27,20 +27,20 @@ import java.io.File;
import java.util.Set;
/**
* Basic contract for performing instrumentation
* Basic contract for performing instrumentation.
*
* @author Steve Ebersole
*/
public interface Instrumenter {
/**
* Perform the instrumentation
* Perform the instrumentation.
*
* @param files The file on which to perform instrumentation
*/
public void execute(Set<File> files);
/**
* Instrumentation options
* Instrumentation options.
*/
public static interface Options {
/**

View File

@ -30,13 +30,38 @@ package org.hibernate.bytecode.buildtime.spi;
* @author Steve Ebersole
*/
public interface Logger {
/**
* Log a message with TRACE semantics.
*
* @param message The message to log.
*/
public void trace(String message);
/**
* Log a message with DEBUG semantics.
*
* @param message The message to log.
*/
public void debug(String message);
/**
* Log a message with INFO semantics.
*
* @param message The message to log.
*/
public void info(String message);
/**
* Log a message with WARN semantics.
*
* @param message The message to log.
*/
public void warn(String message);
/**
* Log a message with ERROR semantics.
*
* @param message The message to log.
*/
public void error(String message);
}

View File

@ -0,0 +1,6 @@
/**
* Package defining build-time bytecode code enhancement (instrumentation) support.
*
* This package should mostly be considered deprecated in favor of {@link org.hibernate.bytecode.enhance}
*/
package org.hibernate.bytecode.buildtime.spi;

View File

@ -26,14 +26,18 @@ package org.hibernate.bytecode.enhance;
import org.hibernate.HibernateException;
/**
* An exception indicating some kind of problem performing bytecode enhancement.
*
* @author Steve Ebersole
*/
public class EnhancementException extends HibernateException {
public EnhancementException(String message) {
super( message );
}
public EnhancementException(String message, Throwable root) {
super( message, root );
/**
* Constructs an EnhancementException
*
* @param message Message explaining the exception condition
* @param cause The underlying cause.
*/
public EnhancementException(String message, Throwable cause) {
super( message, cause );
}
}

View File

@ -0,0 +1,4 @@
/**
* Package defining bytecode code enhancement (instrumentation) support.
*/
package org.hibernate.bytecode.enhance;

View File

@ -27,8 +27,18 @@ import javassist.CtClass;
import javassist.CtField;
/**
* todo : not sure its a great idea to expose Javassist classes this way.
* maybe wrap them in our own contracts?
* The context for performing an enhancement. Enhancement can happen in any number of ways:<ul>
* <li>Build time, via Ant</li>
* <li>Build time, via Maven</li>
* <li>Build time, via Gradle</li>
* <li>Runtime, via agent</li>
* <li>Runtime, via JPA constructs</li>
* </ul>
*
* This interface isolates the code that actually does the enhancement from the underlying context in which
* the enhancement is being performed.
*
* @todo Not sure its a great idea to expose Javassist classes this way. maybe wrap them in our own contracts?
*
* @author Steve Ebersole
*/
@ -37,6 +47,8 @@ public interface EnhancementContext {
* Obtain access to the ClassLoader that can be used to load Class references. In JPA SPI terms, this
* should be a "temporary class loader" as defined by
* {@link javax.persistence.spi.PersistenceUnitInfo#getNewTempClassLoader()}
*
* @return The class loader that the enhancer can use.
*/
public ClassLoader getLoadingClassLoader();
@ -68,6 +80,13 @@ public interface EnhancementContext {
*/
public boolean doDirtyCheckingInline(CtClass classDescriptor);
/**
* Does the given class define any lazy loadable attributes?
*
* @param classDescriptor The class to check
*
* @return true/false
*/
public boolean hasLazyLoadableAttributes(CtClass classDescriptor);
// todo : may be better to invert these 2 such that the context is asked for an ordered list of persistent fields for an entity/composite
@ -75,14 +94,14 @@ public interface EnhancementContext {
/**
* Does the field represent persistent state? Persistent fields will be "enhanced".
* <p/>
// may be better to perform basic checks in the caller (non-static, etc) and call out with just the
// Class name and field name...
* may be better to perform basic checks in the caller (non-static, etc) and call out with just the
* Class name and field name...
*
* @param ctField The field reference.
*
* @return {@code true} if the field is ; {@code false} otherwise.
*/
public boolean isPersistentField(CtField ctField);
public boolean isPersistentField(CtField ctField);
/**
* For fields which are persistent (according to {@link #isPersistentField}), determine the corresponding ordering
@ -94,5 +113,12 @@ public interface EnhancementContext {
*/
public CtField[] order(CtField[] persistentFields);
/**
* Determine if a field is lazy loadable.
*
* @param field The field to check
*
* @return {@code true} if the field is lazy loadable; {@code false} otherwise.
*/
public boolean isLazyLoadable(CtField field);
}

View File

@ -29,10 +29,8 @@ import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.ClassPool;
@ -65,36 +63,16 @@ import org.hibernate.engine.spi.ManagedEntity;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.mapping.PersistentClass;
/**
* Class responsible for performing enhancement.
*
* @author Steve Ebersole
* @author Jason Greene
*/
public class Enhancer {
private static final CoreMessageLogger log = Logger.getMessageLogger( CoreMessageLogger.class, Enhancer.class.getName() );
public static final String PERSISTENT_FIELD_READER_PREFIX = "$$_hibernate_read_";
public static final String PERSISTENT_FIELD_WRITER_PREFIX = "$$_hibernate_write_";
public static final String ENTITY_INSTANCE_GETTER_NAME = "$$_hibernate_getEntityInstance";
public static final String ENTITY_ENTRY_FIELD_NAME = "$$_hibernate_entityEntryHolder";
public static final String ENTITY_ENTRY_GETTER_NAME = "$$_hibernate_getEntityEntry";
public static final String ENTITY_ENTRY_SETTER_NAME = "$$_hibernate_setEntityEntry";
public static final String PREVIOUS_FIELD_NAME = "$$_hibernate_previousManagedEntity";
public static final String PREVIOUS_GETTER_NAME = "$$_hibernate_getPreviousManagedEntity";
public static final String PREVIOUS_SETTER_NAME = "$$_hibernate_setPreviousManagedEntity";
public static final String NEXT_FIELD_NAME = "$$_hibernate_nextManagedEntity";
public static final String NEXT_GETTER_NAME = "$$_hibernate_getNextManagedEntity";
public static final String NEXT_SETTER_NAME = "$$_hibernate_setNextManagedEntity";
public static final String INTERCEPTOR_FIELD_NAME = "$$_hibernate_attributeInterceptor";
public static final String INTERCEPTOR_GETTER_NAME = "$$_hibernate_getInterceptor";
public static final String INTERCEPTOR_SETTER_NAME = "$$_hibernate_setInterceptor";
private final EnhancementContext enhancementContext;
private final ClassPool classPool;
@ -105,6 +83,12 @@ public class Enhancer {
private final CtClass entityEntryCtClass;
private final CtClass objectCtClass;
/**
* Constructs the Enhancer, using the given context.
*
* @param enhancementContext Describes the context in which enhancement will occur so as to give access
* to contextual/environmental information.
*/
public Enhancer(EnhancementContext enhancementContext) {
this.enhancementContext = enhancementContext;
this.classPool = buildClassPool( enhancementContext );
@ -154,8 +138,8 @@ public class Enhancer {
}
private ClassPool buildClassPool(EnhancementContext enhancementContext) {
ClassPool classPool = new ClassPool( false );
ClassLoader loadingClassLoader = enhancementContext.getLoadingClassLoader();
final ClassPool classPool = new ClassPool( false );
final ClassLoader loadingClassLoader = enhancementContext.getLoadingClassLoader();
if ( loadingClassLoader != null ) {
classPool.appendClassPath( new LoaderClassPath( loadingClassLoader ) );
}
@ -171,7 +155,7 @@ public class Enhancer {
* @return The enhanced bytecode. Could be the same as the original bytecode if the original was
* already enhanced or we could not enhance it for some reason.
*
* @throws EnhancementException
* @throws EnhancementException Indicates a problem performing the enhancement
*/
public byte[] enhance(String className, byte[] originalBytes) throws EnhancementException {
final CtClass managedCtClass;
@ -185,27 +169,27 @@ public class Enhancer {
enhance( managedCtClass );
DataOutputStream out = null;
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final DataOutputStream out;
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
out = new DataOutputStream( byteStream );
managedCtClass.toBytecode( out );
return byteStream.toByteArray();
try {
managedCtClass.toBytecode( out );
return byteStream.toByteArray();
}
finally {
try {
out.close();
}
catch (IOException e) {
//swallow
}
}
}
catch (Exception e) {
log.unableToTransformClass( e.getMessage() );
throw new HibernateException( "Unable to transform class: " + e.getMessage() );
}
finally {
try {
if ( out != null ) {
out.close();
}
}
catch (IOException e) {
//swallow
}
}
}
private void enhance(CtClass managedCtClass) {
@ -261,7 +245,7 @@ public class Enhancer {
managedCtClass.addMethod(
CtNewMethod.make(
objectCtClass,
ENTITY_INSTANCE_GETTER_NAME,
EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME,
new CtClass[0],
new CtClass[0],
"{ return this; }",
@ -284,9 +268,9 @@ public class Enhancer {
addFieldWithGetterAndSetter(
managedCtClass,
entityEntryCtClass,
ENTITY_ENTRY_FIELD_NAME,
ENTITY_ENTRY_GETTER_NAME,
ENTITY_ENTRY_SETTER_NAME
EnhancerConstants.ENTITY_ENTRY_FIELD_NAME,
EnhancerConstants.ENTITY_ENTRY_GETTER_NAME,
EnhancerConstants.ENTITY_ENTRY_SETTER_NAME
);
}
@ -294,9 +278,9 @@ public class Enhancer {
addFieldWithGetterAndSetter(
managedCtClass,
managedEntityCtClass,
PREVIOUS_FIELD_NAME,
PREVIOUS_GETTER_NAME,
PREVIOUS_SETTER_NAME
EnhancerConstants.PREVIOUS_FIELD_NAME,
EnhancerConstants.PREVIOUS_GETTER_NAME,
EnhancerConstants.PREVIOUS_SETTER_NAME
);
}
@ -304,9 +288,9 @@ public class Enhancer {
addFieldWithGetterAndSetter(
managedCtClass,
managedEntityCtClass,
NEXT_FIELD_NAME,
NEXT_GETTER_NAME,
NEXT_SETTER_NAME
EnhancerConstants.NEXT_FIELD_NAME,
EnhancerConstants.NEXT_GETTER_NAME,
EnhancerConstants.NEXT_SETTER_NAME
);
}
@ -400,9 +384,9 @@ public class Enhancer {
addFieldWithGetterAndSetter(
managedCtClass,
attributeInterceptorCtClass,
INTERCEPTOR_FIELD_NAME,
INTERCEPTOR_GETTER_NAME,
INTERCEPTOR_SETTER_NAME
EnhancerConstants.INTERCEPTOR_FIELD_NAME,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
EnhancerConstants.INTERCEPTOR_SETTER_NAME
);
}
@ -445,7 +429,8 @@ public class Enhancer {
theField.setModifiers( theField.getModifiers() | Modifier.TRANSIENT );
}
theField.setModifiers( Modifier.setPrivate( theField.getModifiers() ) );
AnnotationsAttribute annotationsAttribute = getVisibleAnnotations( theField.getFieldInfo() );
final AnnotationsAttribute annotationsAttribute = getVisibleAnnotations( theField.getFieldInfo() );
annotationsAttribute.addAnnotation( new Annotation( Transient.class.getName(), constPool ) );
return theField;
}
@ -490,7 +475,7 @@ public class Enhancer {
final FieldInfo fieldInfo = persistentField.getFieldInfo();
final String fieldName = fieldInfo.getName();
final String readerName = PERSISTENT_FIELD_READER_PREFIX + fieldName;
final String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName;
// read attempts only have to deal lazy-loading support, not dirty checking; so if the field
// is not enabled as lazy-loadable return a plain simple getter as the reader
@ -498,7 +483,7 @@ public class Enhancer {
// not lazy-loadable...
// EARLY RETURN!!!
try {
CtMethod reader = CtNewMethod.getter( readerName, persistentField );
final CtMethod reader = CtNewMethod.getter( readerName, persistentField );
managedCtClass.addMethod( reader );
return reader;
}
@ -515,11 +500,11 @@ public class Enhancer {
}
// temporary solution...
String methodBody = typeDescriptor.buildReadInterceptionBodyFragment( fieldName )
final String methodBody = typeDescriptor.buildReadInterceptionBodyFragment( fieldName )
+ " return this." + fieldName + ";";
try {
CtMethod reader = CtNewMethod.make(
final CtMethod reader = CtNewMethod.make(
Modifier.PRIVATE,
persistentField.getType(),
readerName,
@ -550,7 +535,7 @@ public class Enhancer {
final FieldInfo fieldInfo = persistentField.getFieldInfo();
final String fieldName = fieldInfo.getName();
final String writerName = PERSISTENT_FIELD_WRITER_PREFIX + fieldName;
final String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName;
final CtMethod writer;
@ -560,7 +545,7 @@ public class Enhancer {
writer = CtNewMethod.setter( writerName, persistentField );
}
else {
String methodBody = typeDescriptor.buildWriteInterceptionBodyFragment( fieldName );
final String methodBody = typeDescriptor.buildWriteInterceptionBodyFragment( fieldName );
writer = CtNewMethod.make(
Modifier.PRIVATE,
CtClass.voidType,
@ -602,15 +587,15 @@ public class Enhancer {
final String methodName = methodInfo.getName();
// skip methods added by enhancement
if ( methodName.startsWith( PERSISTENT_FIELD_READER_PREFIX )
|| methodName.startsWith( PERSISTENT_FIELD_WRITER_PREFIX )
|| methodName.equals( ENTITY_INSTANCE_GETTER_NAME )
|| methodName.equals( ENTITY_ENTRY_GETTER_NAME )
|| methodName.equals( ENTITY_ENTRY_SETTER_NAME )
|| methodName.equals( PREVIOUS_GETTER_NAME )
|| methodName.equals( PREVIOUS_SETTER_NAME )
|| methodName.equals( NEXT_GETTER_NAME )
|| methodName.equals( NEXT_SETTER_NAME ) ) {
if ( methodName.startsWith( EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX )
|| methodName.startsWith( EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX )
|| methodName.equals( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME )
|| methodName.equals( EnhancerConstants.ENTITY_ENTRY_GETTER_NAME )
|| methodName.equals( EnhancerConstants.ENTITY_ENTRY_SETTER_NAME )
|| methodName.equals( EnhancerConstants.PREVIOUS_GETTER_NAME )
|| methodName.equals( EnhancerConstants.PREVIOUS_SETTER_NAME )
|| methodName.equals( EnhancerConstants.NEXT_GETTER_NAME )
|| methodName.equals( EnhancerConstants.NEXT_SETTER_NAME ) ) {
continue;
}
@ -621,15 +606,15 @@ public class Enhancer {
}
try {
CodeIterator itr = codeAttr.iterator();
final CodeIterator itr = codeAttr.iterator();
while ( itr.hasNext() ) {
int index = itr.next();
int op = itr.byteAt( index );
final int index = itr.next();
final int op = itr.byteAt( index );
if ( op != Opcode.PUTFIELD && op != Opcode.GETFIELD ) {
continue;
}
int constIndex = itr.u16bitAt( index+1 );
final int constIndex = itr.u16bitAt( index+1 );
final String fieldName = constPool.getFieldrefName( constIndex );
final PersistentAttributeDescriptor attributeDescriptor = attributeDescriptorMap.get( fieldName );
@ -646,27 +631,27 @@ public class Enhancer {
);
if ( op == Opcode.GETFIELD ) {
int read_method_index = constPool.addMethodrefInfo(
final int readMethodIndex = constPool.addMethodrefInfo(
constPool.getThisClassInfo(),
attributeDescriptor.getReader().getName(),
attributeDescriptor.getReader().getSignature()
);
itr.writeByte( Opcode.INVOKESPECIAL, index );
itr.write16bit( read_method_index, index+1 );
itr.write16bit( readMethodIndex, index+1 );
}
else {
int write_method_index = constPool.addMethodrefInfo(
final int writeMethodIndex = constPool.addMethodrefInfo(
constPool.getThisClassInfo(),
attributeDescriptor.getWriter().getName(),
attributeDescriptor.getWriter().getSignature()
);
itr.writeByte( Opcode.INVOKESPECIAL, index );
itr.write16bit( write_method_index, index+1 );
itr.write16bit( writeMethodIndex, index+1 );
}
}
StackMapTable smt = MapMaker.make( classPool, methodInfo );
methodInfo.getCodeAttribute().setAttribute(smt);
final StackMapTable smt = MapMaker.make( classPool, methodInfo );
methodInfo.getCodeAttribute().setAttribute( smt );
}
catch (BadBytecode e) {
throw new EnhancementException(
@ -748,7 +733,7 @@ public class Enhancer {
}
}
private static abstract class AbstractAttributeTypeDescriptor implements AttributeTypeDescriptor {
private abstract static class AbstractAttributeTypeDescriptor implements AttributeTypeDescriptor {
@Override
public String buildInLineDirtyCheckingBodyFragment(String fieldName) {
// for now...

View File

@ -0,0 +1,133 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.bytecode.enhance.spi;
/**
* Constants used during enhancement.
*
* @author Steve Ebersole
*/
public class EnhancerConstants {
/**
* Prefix for persistent-field reader methods.
*/
public static final String PERSISTENT_FIELD_READER_PREFIX = "$$_hibernate_read_";
/**
* Prefix for persistent-field writer methods.
*/
public static final String PERSISTENT_FIELD_WRITER_PREFIX = "$$_hibernate_write_";
/**
* Name of the method used to get reference the the entity instance (this in the case of enhanced classes).
*/
public static final String ENTITY_INSTANCE_GETTER_NAME = "$$_hibernate_getEntityInstance";
/**
* Name of the field used to hold the {@link org.hibernate.engine.spi.EntityEntry}
*/
public static final String ENTITY_ENTRY_FIELD_NAME = "$$_hibernate_entityEntryHolder";
/**
* Name of the method used to read the {@link org.hibernate.engine.spi.EntityEntry} field.
*
* @see #ENTITY_ENTRY_FIELD_NAME
*/
public static final String ENTITY_ENTRY_GETTER_NAME = "$$_hibernate_getEntityEntry";
/**
* Name of the method used to write the {@link org.hibernate.engine.spi.EntityEntry} field.
*
* @see #ENTITY_ENTRY_FIELD_NAME
*/
public static final String ENTITY_ENTRY_SETTER_NAME = "$$_hibernate_setEntityEntry";
/**
* Name of the field used to hold the previous {@link org.hibernate.engine.spi.ManagedEntity}.
*
* Together, previous/next are used to define a "linked list"
*
* @see #NEXT_FIELD_NAME
*/
public static final String PREVIOUS_FIELD_NAME = "$$_hibernate_previousManagedEntity";
/**
* Name of the method used to read the previous {@link org.hibernate.engine.spi.ManagedEntity} field
*
* @see #PREVIOUS_FIELD_NAME
*/
public static final String PREVIOUS_GETTER_NAME = "$$_hibernate_getPreviousManagedEntity";
/**
* Name of the method used to write the previous {@link org.hibernate.engine.spi.ManagedEntity} field
*
* @see #PREVIOUS_FIELD_NAME
*/
public static final String PREVIOUS_SETTER_NAME = "$$_hibernate_setPreviousManagedEntity";
/**
* Name of the field used to hold the previous {@link org.hibernate.engine.spi.ManagedEntity}.
*
* Together, previous/next are used to define a "linked list"
*
* @see #PREVIOUS_FIELD_NAME
*/
public static final String NEXT_FIELD_NAME = "$$_hibernate_nextManagedEntity";
/**
* Name of the method used to read the next {@link org.hibernate.engine.spi.ManagedEntity} field
*
* @see #NEXT_FIELD_NAME
*/
public static final String NEXT_GETTER_NAME = "$$_hibernate_getNextManagedEntity";
/**
* Name of the method used to write the next {@link org.hibernate.engine.spi.ManagedEntity} field
*
* @see #NEXT_FIELD_NAME
*/
public static final String NEXT_SETTER_NAME = "$$_hibernate_setNextManagedEntity";
/**
* Name of the field used to store the {@link org.hibernate.engine.spi.PersistentAttributeInterceptable}.
*/
public static final String INTERCEPTOR_FIELD_NAME = "$$_hibernate_attributeInterceptor";
/**
* Name of the method used to read the interceptor
*
* @see #INTERCEPTOR_FIELD_NAME
*/
public static final String INTERCEPTOR_GETTER_NAME = "$$_hibernate_getInterceptor";
/**
* Name of the method used to write the interceptor
*
* @see #INTERCEPTOR_FIELD_NAME
*/
public static final String INTERCEPTOR_SETTER_NAME = "$$_hibernate_setInterceptor";
private EnhancerConstants() {
}
}

View File

@ -0,0 +1,4 @@
/**
* Package defining bytecode code enhancement (instrumentation) support.
*/
package org.hibernate.bytecode.enhance.spi;

View File

@ -46,14 +46,18 @@ public class FieldInterceptionHelper {
private static final Set<Delegate> INSTRUMENTATION_DELEGATES = buildInstrumentationDelegates();
private static Set<Delegate> buildInstrumentationDelegates() {
HashSet<Delegate> delegates = new HashSet<Delegate>();
final HashSet<Delegate> delegates = new HashSet<Delegate>();
delegates.add( JavassistDelegate.INSTANCE );
return delegates;
}
private FieldInterceptionHelper() {
}
/**
* Utility to check to see if a given entity class is instrumented.
*
* @param entityClass The entity class to check
*
* @return {@code true} if it has been instrumented; {@code false} otherwise
*/
public static boolean isInstrumented(Class entityClass) {
for ( Delegate delegate : INSTRUMENTATION_DELEGATES ) {
if ( delegate.isInstrumented( entityClass ) ) {
@ -63,17 +67,34 @@ public class FieldInterceptionHelper {
return false;
}
public static boolean isInstrumented(Object entity) {
return entity != null && isInstrumented( entity.getClass() );
/**
* Utility to check to see if a given object is an instance of an instrumented class. If the instance
* is {@code null}, the check returns {@code false}
*
* @param object The object to check
*
* @return {@code true} if it has been instrumented; {@code false} otherwise
*/
public static boolean isInstrumented(Object object) {
return object != null && isInstrumented( object.getClass() );
}
public static FieldInterceptor extractFieldInterceptor(Object entity) {
if ( entity == null ) {
/**
* Assuming the given object is an enhanced entity, extract and return its interceptor. Will
* return {@code null} if object is {@code null}, or if the object was deemed to not be
* instrumented
*
* @param object The object from which to extract the interceptor
*
* @return The extracted interceptor, or {@code null}
*/
public static FieldInterceptor extractFieldInterceptor(Object object) {
if ( object == null ) {
return null;
}
FieldInterceptor interceptor = null;
for ( Delegate delegate : INSTRUMENTATION_DELEGATES ) {
interceptor = delegate.extractInterceptor( entity );
interceptor = delegate.extractInterceptor( object );
if ( interceptor != null ) {
break;
}
@ -81,12 +102,21 @@ public class FieldInterceptionHelper {
return interceptor;
}
/**
* Assuming the given object is an enhanced entity, inject a field interceptor.
*
* @param entity The entity instance
* @param entityName The entity name
* @param uninitializedFieldNames The names of any uninitialized fields
* @param session The session
*
* @return The injected interceptor
*/
public static FieldInterceptor injectFieldInterceptor(
Object entity,
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) {
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) {
if ( entity == null ) {
return null;
}
@ -144,4 +174,8 @@ public class FieldInterceptionHelper {
return null;
}
}
private FieldInterceptionHelper() {
}
}

View File

@ -47,7 +47,7 @@ import org.hibernate.proxy.LazyInitializer;
* @author Steve Ebersole
*/
@SuppressWarnings( {"UnnecessaryUnboxing", "UnnecessaryBoxing"})
public final class FieldInterceptorImpl extends AbstractFieldInterceptor implements FieldHandler, Serializable {
final class FieldInterceptorImpl extends AbstractFieldInterceptor implements FieldHandler, Serializable {
FieldInterceptorImpl(SessionImplementor session, Set uninitializedFields, String entityName) {
super( session, uninitializedFields, entityName );
@ -57,46 +57,41 @@ public final class FieldInterceptorImpl extends AbstractFieldInterceptor impleme
// FieldHandler impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public boolean readBoolean(Object target, String name, boolean oldValue) {
return ( ( Boolean ) intercept( target, name, oldValue ) )
.booleanValue();
return ( (Boolean) intercept( target, name, oldValue ) ).booleanValue();
}
public byte readByte(Object target, String name, byte oldValue) {
return ( ( Byte ) intercept( target, name, Byte.valueOf( oldValue ) ) ).byteValue();
return ( (Byte) intercept( target, name, Byte.valueOf( oldValue ) ) ).byteValue();
}
public char readChar(Object target, String name, char oldValue) {
return ( ( Character ) intercept( target, name, Character.valueOf( oldValue ) ) )
.charValue();
return ( (Character) intercept( target, name, Character.valueOf( oldValue ) ) ).charValue();
}
public double readDouble(Object target, String name, double oldValue) {
return ( ( Double ) intercept( target, name, Double.valueOf( oldValue ) ) )
.doubleValue();
return ( (Double) intercept( target, name, Double.valueOf( oldValue ) ) ).doubleValue();
}
public float readFloat(Object target, String name, float oldValue) {
return ( ( Float ) intercept( target, name, Float.valueOf( oldValue ) ) )
.floatValue();
return ( (Float) intercept( target, name, Float.valueOf( oldValue ) ) ).floatValue();
}
public int readInt(Object target, String name, int oldValue) {
return ( ( Integer ) intercept( target, name, Integer.valueOf( oldValue ) ) );
return ( (Integer) intercept( target, name, Integer.valueOf( oldValue ) ) );
}
public long readLong(Object target, String name, long oldValue) {
return ( ( Long ) intercept( target, name, Long.valueOf( oldValue ) ) ).longValue();
return ( (Long) intercept( target, name, Long.valueOf( oldValue ) ) ).longValue();
}
public short readShort(Object target, String name, short oldValue) {
return ( ( Short ) intercept( target, name, Short.valueOf( oldValue ) ) )
.shortValue();
return ( (Short) intercept( target, name, Short.valueOf( oldValue ) ) ).shortValue();
}
public Object readObject(Object target, String name, Object oldValue) {
Object value = intercept( target, name, oldValue );
if (value instanceof HibernateProxy) {
LazyInitializer li = ( (HibernateProxy) value ).getHibernateLazyInitializer();
if ( value instanceof HibernateProxy ) {
final LazyInitializer li = ( (HibernateProxy) value ).getHibernateLazyInitializer();
if ( li.isUnwrap() ) {
value = li.getImplementation();
}
@ -159,11 +154,10 @@ public final class FieldInterceptorImpl extends AbstractFieldInterceptor impleme
}
public String toString() {
return "FieldInterceptorImpl(" +
"entityName=" + getEntityName() +
",dirty=" + isDirty() +
",uninitializedFields=" + getUninitializedFields() +
')';
return "FieldInterceptorImpl(entityName=" + getEntityName() +
",dirty=" + isDirty() +
",uninitializedFields=" + getUninitializedFields() +
')';
}
}
}

View File

@ -30,23 +30,42 @@ import org.hibernate.bytecode.internal.javassist.FieldHandled;
import org.hibernate.engine.spi.SessionImplementor;
/**
* Javassist specific helper
*
* @author Steve Ebersole
*/
public class JavassistHelper {
private JavassistHelper() {
}
/**
* Perform the Javassist-specific field interceptor extraction
*
* @param entity The entity from which to extract the interceptor
*
* @return The extracted interceptor
*/
public static FieldInterceptor extractFieldInterceptor(Object entity) {
return ( FieldInterceptor ) ( ( FieldHandled ) entity ).getFieldHandler();
return (FieldInterceptor) ( (FieldHandled) entity ).getFieldHandler();
}
/**
* Perform the Javassist-specific field interceptor injection
*
* @param entity The entity instance
* @param entityName The entity name
* @param uninitializedFieldNames The names of any uninitialized fields
* @param session The session
*
* @return The generated and injected interceptor
*/
public static FieldInterceptor injectFieldInterceptor(
Object entity,
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) {
FieldInterceptorImpl fieldInterceptor = new FieldInterceptorImpl( session, uninitializedFieldNames, entityName );
( ( FieldHandled ) entity ).setFieldHandler( fieldInterceptor );
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) {
final FieldInterceptorImpl fieldInterceptor = new FieldInterceptorImpl( session, uninitializedFieldNames, entityName );
( (FieldHandled) entity ).setFieldHandler( fieldInterceptor );
return fieldInterceptor;
}
}

View File

@ -0,0 +1,4 @@
/**
* Javassist support internals
*/
package org.hibernate.bytecode.instrumentation.internal.javassist;

View File

@ -0,0 +1,4 @@
/**
* Bytecode instrumentation internals
*/
package org.hibernate.bytecode.instrumentation.internal;

View File

@ -29,6 +29,8 @@ import org.hibernate.LazyInitializationException;
import org.hibernate.engine.spi.SessionImplementor;
/**
* Base support for FieldInterceptor implementations.
*
* @author Steve Ebersole
*/
public abstract class AbstractFieldInterceptor implements FieldInterceptor, Serializable {
@ -49,26 +51,32 @@ public abstract class AbstractFieldInterceptor implements FieldInterceptor, Seri
// FieldInterceptor impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public final void setSession(SessionImplementor session) {
this.session = session;
}
@Override
public final boolean isInitialized() {
return uninitializedFields == null || uninitializedFields.size() == 0;
}
@Override
public final boolean isInitialized(String field) {
return uninitializedFields == null || !uninitializedFields.contains( field );
}
@Override
public final void dirty() {
dirty = true;
}
@Override
public final boolean isDirty() {
return dirty;
}
@Override
public final void clearDirty() {
dirty = false;
}
@ -76,6 +84,15 @@ public abstract class AbstractFieldInterceptor implements FieldInterceptor, Seri
// subclass accesses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Interception of access to the named field
*
* @param target The call target
* @param fieldName The name of the field.
* @param value The value.
*
* @return ?
*/
protected final Object intercept(Object target, String fieldName, Object value) {
if ( initializing ) {
return value;
@ -92,14 +109,14 @@ public abstract class AbstractFieldInterceptor implements FieldInterceptor, Seri
final Object result;
initializing = true;
try {
result = ( ( LazyPropertyInitializer ) session.getFactory()
.getEntityPersister( entityName ) )
result = ( (LazyPropertyInitializer) session.getFactory().getEntityPersister( entityName ) )
.initializeLazyProperty( fieldName, target, session );
}
finally {
initializing = false;
}
uninitializedFields = null; //let's assume that there is only one lazy fetch group, for now!
// let's assume that there is only one lazy fetch group, for now!
uninitializedFields = null;
return result;
}
else {
@ -107,18 +124,38 @@ public abstract class AbstractFieldInterceptor implements FieldInterceptor, Seri
}
}
/**
* Access to the session
*
* @return The associated session
*/
public final SessionImplementor getSession() {
return session;
}
/**
* Access to all currently uninitialized fields
*
* @return The name of all currently uninitialized fields
*/
public final Set getUninitializedFields() {
return uninitializedFields;
}
/**
* Access to the intercepted entity name
*
* @return The entity name
*/
public final String getEntityName() {
return entityName;
}
/**
* Is the instance currently initializing?
*
* @return true/false.
*/
public final boolean isInitializing() {
return initializing;
}

View File

@ -35,19 +35,21 @@ import org.hibernate.engine.spi.SessionImplementor;
public interface LazyPropertyInitializer {
/**
* Marker value for uninitialized properties
* Marker value for uninitialized properties.
*/
public static final Serializable UNFETCHED_PROPERTY = new Serializable() {
@Override
public String toString() {
return "<lazy>";
}
public Object readResolve() {
return UNFETCHED_PROPERTY;
}
};
/**
* Initialize the property, and return its new value
* Initialize the property, and return its new value.
*
* @param fieldName The name of the field being initialized
* @param entity The entity on which the initialization is occurring

View File

@ -0,0 +1,6 @@
/**
* Package defining bytecode code enhancement (instrumentation) support.
*
* This package should mostly be considered deprecated in favor of {@link org.hibernate.bytecode.enhance}
*/
package org.hibernate.bytecode.instrumentation.spi;

View File

@ -27,6 +27,7 @@ import java.io.Serializable;
import org.hibernate.PropertyAccessException;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.cfg.AvailableSettings;
/**
* The {@link org.hibernate.bytecode.spi.ReflectionOptimizer.AccessOptimizer} implementation for Javassist
@ -36,24 +37,36 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer;
*/
public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimizer, Serializable {
public static final String PROPERTY_GET_EXCEPTION =
"exception getting property value with Javassist (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
private static final String PROPERTY_GET_EXCEPTION = String.format(
"exception getting property value with Javassist (set %s to false for more info)",
AvailableSettings.USE_REFLECTION_OPTIMIZER
);
public static final String PROPERTY_SET_EXCEPTION =
"exception setting property value with Javassist (set hibernate.bytecode.use_reflection_optimizer=false for more info)";
private static final String PROPERTY_SET_EXCEPTION = String.format(
"exception setting property value with Javassist (set %s to false for more info)",
AvailableSettings.USE_REFLECTION_OPTIMIZER
);
private final BulkAccessor bulkAccessor;
private final Class mappedClass;
/**
* Constructs an AccessOptimizerAdapter
*
* @param bulkAccessor The bulk accessor to use
* @param mappedClass The mapped class
*/
public AccessOptimizerAdapter(BulkAccessor bulkAccessor, Class mappedClass) {
this.bulkAccessor = bulkAccessor;
this.mappedClass = mappedClass;
}
@Override
public String[] getPropertyNames() {
return bulkAccessor.getGetters();
}
@Override
public Object[] getPropertyValues(Object object) {
try {
return bulkAccessor.getPropertyValues( object );
@ -61,14 +74,15 @@ public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimiz
catch ( Throwable t ) {
throw new PropertyAccessException(
t,
PROPERTY_GET_EXCEPTION,
false,
mappedClass,
getterName( t, bulkAccessor )
);
PROPERTY_GET_EXCEPTION,
false,
mappedClass,
getterName( t, bulkAccessor )
);
}
}
@Override
public void setPropertyValues(Object object, Object[] values) {
try {
bulkAccessor.setPropertyValues( object, values );
@ -76,10 +90,10 @@ public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimiz
catch ( Throwable t ) {
throw new PropertyAccessException(
t,
PROPERTY_SET_EXCEPTION,
true,
mappedClass,
setterName( t, bulkAccessor )
PROPERTY_SET_EXCEPTION,
true,
mappedClass,
setterName( t, bulkAccessor )
);
}
}

View File

@ -26,22 +26,36 @@ package org.hibernate.bytecode.internal.javassist;
import java.io.Serializable;
/**
* A JavaBean accessor.
* <p/>
* <p>This object provides methods that set/get multiple properties
* of a JavaBean at once. This class and its support classes have been
* developed for the comaptibility with cglib
* (<tt>http://cglib.sourceforge.net/</tt>).
* A JavaBean bulk accessor, which provides methods capable of getting/setting multiple properties
* of a JavaBean at once.
*
* @author Muga Nishizawa
* @author modified by Shigeru Chiba
* @author Shigeru Chiba
*/
public abstract class BulkAccessor implements Serializable {
protected Class target;
protected String[] getters, setters;
protected Class[] types;
protected BulkAccessor() {
/**
* Creates a new instance of BulkAccessor. The created instance provides methods for setting/getting
* specified properties at once.
*
* @param beanClass the class of the JavaBeans accessed
* through the created object.
* @param getters the names of setter methods for specified properties.
* @param setters the names of getter methods for specified properties.
* @param types the types of specified properties.
*
* @return The created bulk accessor
*/
public static BulkAccessor create(
Class beanClass,
String[] getters,
String[] setters,
Class[] types) {
final BulkAccessorFactory factory = new BulkAccessorFactory( beanClass, getters, setters, types );
return factory.create();
}
/**
@ -64,15 +78,19 @@ public abstract class BulkAccessor implements Serializable {
* Returns the values of properties of a given bean.
*
* @param bean JavaBean.
*
* @return The property values
*/
public Object[] getPropertyValues(Object bean) {
Object[] values = new Object[getters.length];
final Object[] values = new Object[getters.length];
getPropertyValues( bean, values );
return values;
}
/**
* Returns the types of properties.
*
* @return The property types
*/
public Class[] getPropertyTypes() {
return types.clone();
@ -80,6 +98,8 @@ public abstract class BulkAccessor implements Serializable {
/**
* Returns the setter names of properties.
*
* @return The getter names
*/
public String[] getGetters() {
return getters.clone();
@ -87,28 +107,13 @@ public abstract class BulkAccessor implements Serializable {
/**
* Returns the getter names of the properties.
*
* @return The setter names
*/
public String[] getSetters() {
return setters.clone();
}
/**
* Creates a new instance of <code>BulkAccessor</code>.
* The created instance provides methods for setting/getting
* specified properties at once.
*
* @param beanClass the class of the JavaBeans accessed
* through the created object.
* @param getters the names of setter methods for specified properties.
* @param setters the names of getter methods for specified properties.
* @param types the types of specified properties.
*/
public static BulkAccessor create(
Class beanClass,
String[] getters,
String[] setters,
Class[] types) {
BulkAccessorFactory factory = new BulkAccessorFactory( beanClass, getters, setters, types );
return factory.create();
private BulkAccessor() {
}
}

View File

@ -23,79 +23,64 @@
*/
package org.hibernate.bytecode.internal.javassist;
import org.hibernate.HibernateException;
/**
* An exception thrown while generating a bulk accessor.
*
*
* @author Muga Nishizawa
* @author modified by Shigeru Chiba
*/
public class BulkAccessorException extends RuntimeException {
private Throwable myCause;
public class BulkAccessorException extends HibernateException {
private final int index;
/**
* Gets the cause of this throwable.
* It is for JDK 1.3 compatibility.
*/
public Throwable getCause() {
return (myCause == this ? null : myCause);
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
*/
public BulkAccessorException(String message) {
this( message, -1 );
}
/**
* Initializes the cause of this throwable.
* It is for JDK 1.3 compatibility.
*/
public synchronized Throwable initCause(Throwable cause) {
myCause = cause;
return this;
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param index The index of the property that causes an exception.
*/
public BulkAccessorException(String message, int index) {
this( message, index, null );
}
private int index;
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param cause The underlying cause
*/
public BulkAccessorException(String message, Exception cause) {
this( message, -1, cause );
}
/**
* Constructs an exception.
*/
public BulkAccessorException(String message) {
super(message);
index = -1;
initCause(null);
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param index The index of the property that causes an exception.
* @param cause The underlying cause
*/
public BulkAccessorException(String message, int index, Exception cause) {
super( message + " : @" + index, cause );
this.index = index;
}
/**
* Constructs an exception.
*
* @param index the index of the property that causes an exception.
*/
public BulkAccessorException(String message, int index) {
this(message + ": " + index);
this.index = index;
}
/**
* Constructs an exception.
*/
public BulkAccessorException(String message, Throwable cause) {
super(message);
index = -1;
initCause(cause);
}
/**
* Constructs an exception.
*
* @param index the index of the property that causes an exception.
*/
public BulkAccessorException(Throwable cause, int index) {
this("Property " + index);
this.index = index;
initCause(cause);
}
/**
* Returns the index of the property that causes this exception.
*
* @return -1 if the index is not specified.
*/
public int getIndex() {
return this.index;
}
/**
* Returns the index of the property that causes this exception.
*
* @return -1 if the index is not specified.
*/
public int getIndex() {
return this.index;
}
}

View File

@ -54,7 +54,8 @@ class BulkAccessorFactory {
private static final String GET_SETTER_DESC = "(Ljava/lang/Object;[Ljava/lang/Object;)V";
private static final String THROWABLE_CLASS_NAME = Throwable.class.getName();
private static final String BULKEXCEPTION_CLASS_NAME = BulkAccessorException.class.getName();
private static int counter = 0;
private static int counter;
private Class targetBean;
private String[] getterNames;
@ -64,9 +65,9 @@ class BulkAccessorFactory {
BulkAccessorFactory(
Class target,
String[] getterNames,
String[] setterNames,
Class[] types) {
String[] getterNames,
String[] setterNames,
Class[] types) {
this.targetBean = target;
this.getterNames = getterNames;
this.setterNames = setterNames;
@ -75,20 +76,20 @@ class BulkAccessorFactory {
}
BulkAccessor create() {
Method[] getters = new Method[getterNames.length];
Method[] setters = new Method[setterNames.length];
final Method[] getters = new Method[getterNames.length];
final Method[] setters = new Method[setterNames.length];
findAccessors( targetBean, getterNames, setterNames, types, getters, setters );
Class beanClass;
final Class beanClass;
try {
ClassFile classfile = make( getters, setters );
ClassLoader loader = this.getClassLoader();
final ClassFile classfile = make( getters, setters );
final ClassLoader loader = this.getClassLoader();
if ( writeDirectory != null ) {
FactoryHelper.writeFile( classfile, writeDirectory );
}
beanClass = FactoryHelper.toClass( classfile, loader, getDomain() );
return ( BulkAccessor ) this.newInstance( beanClass );
return (BulkAccessor) this.newInstance( beanClass );
}
catch ( Exception e ) {
throw new BulkAccessorException( e.getMessage(), e );
@ -96,7 +97,7 @@ class BulkAccessorFactory {
}
private ProtectionDomain getDomain() {
Class cl;
final Class cl;
if ( this.targetBean != null ) {
cl = this.targetBean;
}
@ -111,10 +112,10 @@ class BulkAccessorFactory {
// set the name of bulk accessor.
className = className + "_$$_bulkaccess_" + counter++;
if ( className.startsWith( "java." ) ) {
className = "org.javassist.tmp." + className;
className = PACKAGE_NAME_PREFIX + className;
}
ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
final ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
classfile.setAccessFlags( AccessFlag.PUBLIC );
addDefaultConstructor( classfile );
addGetter( classfile, getters );
@ -132,9 +133,9 @@ class BulkAccessorFactory {
}
private Object newInstance(Class type) throws Exception {
BulkAccessor instance = ( BulkAccessor ) type.newInstance();
final BulkAccessor instance = (BulkAccessor) type.newInstance();
instance.target = targetBean;
int len = getterNames.length;
final int len = getterNames.length;
instance.getters = new String[len];
instance.setters = new String[len];
instance.types = new Class[len];
@ -150,34 +151,35 @@ class BulkAccessorFactory {
/**
* Declares a constructor that takes no parameter.
*
* @param classfile
* @throws CannotCompileException
* @param classfile The class descriptor
*
* @throws CannotCompileException Indicates trouble with the underlying Javassist calls
*/
private void addDefaultConstructor(ClassFile classfile) throws CannotCompileException {
ConstPool cp = classfile.getConstPool();
String cons_desc = "()V";
MethodInfo mi = new MethodInfo( cp, MethodInfo.nameInit, cons_desc );
final ConstPool constPool = classfile.getConstPool();
final String constructorSignature = "()V";
final MethodInfo constructorMethodInfo = new MethodInfo( constPool, MethodInfo.nameInit, constructorSignature );
Bytecode code = new Bytecode( cp, 0, 1 );
final Bytecode code = new Bytecode( constPool, 0, 1 );
// aload_0
code.addAload( 0 );
// invokespecial
code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, cons_desc );
code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, constructorSignature );
// return
code.addOpcode( Opcode.RETURN );
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
constructorMethodInfo.setCodeAttribute( code.toCodeAttribute() );
constructorMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( constructorMethodInfo );
}
private void addGetter(ClassFile classfile, final Method[] getters) throws CannotCompileException {
ConstPool cp = classfile.getConstPool();
int target_type_index = cp.addClassInfo( this.targetBean.getName() );
String desc = GET_SETTER_DESC;
MethodInfo mi = new MethodInfo( cp, GENERATED_GETTER_NAME, desc );
final ConstPool constPool = classfile.getConstPool();
final int targetBeanConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() );
final String desc = GET_SETTER_DESC;
final MethodInfo getterMethodInfo = new MethodInfo( constPool, GENERATED_GETTER_NAME, desc );
Bytecode code = new Bytecode( cp, 6, 4 );
final Bytecode code = new Bytecode( constPool, 6, 4 );
/* | this | bean | args | raw bean | */
if ( getters.length >= 0 ) {
// aload_1 // load bean
@ -188,12 +190,13 @@ class BulkAccessorFactory {
code.addAstore( 3 );
for ( int i = 0; i < getters.length; ++i ) {
if ( getters[i] != null ) {
Method getter = getters[i];
final Method getter = getters[i];
// aload_2 // args
code.addAload( 2 );
// iconst_i // continue to aastore
code.addIconst( i ); // growing stack is 1
Class returnType = getter.getReturnType();
// growing stack is 1
code.addIconst( i );
final Class returnType = getter.getReturnType();
int typeIndex = -1;
if ( returnType.isPrimitive() ) {
typeIndex = FactoryHelper.typeIndex( returnType );
@ -205,23 +208,24 @@ class BulkAccessorFactory {
// aload_3 // load the raw bean
code.addAload( 3 );
String getter_desc = RuntimeSupport.makeDescriptor( getter );
String getterName = getter.getName();
final String getterSignature = RuntimeSupport.makeDescriptor( getter );
final String getterName = getter.getName();
if ( this.targetBean.isInterface() ) {
// invokeinterface
code.addInvokeinterface( target_type_index, getterName, getter_desc, 1 );
code.addInvokeinterface( targetBeanConstPoolIndex, getterName, getterSignature, 1 );
}
else {
// invokevirtual
code.addInvokevirtual( target_type_index, getterName, getter_desc );
code.addInvokevirtual( targetBeanConstPoolIndex, getterName, getterSignature );
}
if ( typeIndex >= 0 ) { // is a primitive type
if ( typeIndex >= 0 ) {
// is a primitive type
// invokespecial
code.addInvokespecial(
FactoryHelper.wrapperTypes[typeIndex],
MethodInfo.nameInit,
FactoryHelper.wrapperDesc[typeIndex]
MethodInfo.nameInit,
FactoryHelper.wrapperDesc[typeIndex]
);
}
@ -234,22 +238,24 @@ class BulkAccessorFactory {
// return
code.addOpcode( Opcode.RETURN );
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
getterMethodInfo.setCodeAttribute( code.toCodeAttribute() );
getterMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( getterMethodInfo );
}
private void addSetter(ClassFile classfile, final Method[] setters) throws CannotCompileException {
ConstPool cp = classfile.getConstPool();
int target_type_index = cp.addClassInfo( this.targetBean.getName() );
String desc = GET_SETTER_DESC;
MethodInfo mi = new MethodInfo( cp, GENERATED_SETTER_NAME, desc );
final ConstPool constPool = classfile.getConstPool();
final int targetTypeConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() );
final String desc = GET_SETTER_DESC;
final MethodInfo setterMethodInfo = new MethodInfo( constPool, GENERATED_SETTER_NAME, desc );
Bytecode code = new Bytecode( cp, 4, 6 );
final Bytecode code = new Bytecode( constPool, 4, 6 );
StackMapTable stackmap = null;
/* | this | bean | args | i | raw bean | exception | */
if ( setters.length > 0 ) {
int start, end; // required to exception table
// required to exception table
int start;
int end;
// iconst_0 // i
code.addIconst( 0 );
// istore_3 // store i
@ -266,7 +272,7 @@ class BulkAccessorFactory {
int lastIndex = 0;
for ( int i = 0; i < setters.length; ++i ) {
if ( setters[i] != null ) {
int diff = i - lastIndex;
final int diff = i - lastIndex;
if ( diff > 0 ) {
// iinc 3, 1
code.addOpcode( Opcode.IINC );
@ -285,26 +291,26 @@ class BulkAccessorFactory {
// aaload
code.addOpcode( Opcode.AALOAD );
// checkcast
Class[] setterParamTypes = setters[i].getParameterTypes();
Class setterParamType = setterParamTypes[0];
final Class[] setterParamTypes = setters[i].getParameterTypes();
final Class setterParamType = setterParamTypes[0];
if ( setterParamType.isPrimitive() ) {
// checkcast (case of primitive type)
// invokevirtual (case of primitive type)
this.addUnwrapper( classfile, code, setterParamType );
this.addUnwrapper( code, setterParamType );
}
else {
// checkcast (case of reference type)
code.addCheckcast( setterParamType.getName() );
}
/* current stack len = 2 */
String rawSetterMethod_desc = RuntimeSupport.makeDescriptor( setters[i] );
final String rawSetterMethodDesc = RuntimeSupport.makeDescriptor( setters[i] );
if ( !this.targetBean.isInterface() ) {
// invokevirtual
code.addInvokevirtual( target_type_index, setters[i].getName(), rawSetterMethod_desc );
code.addInvokevirtual( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc );
}
else {
// invokeinterface
Class[] params = setters[i].getParameterTypes();
final Class[] params = setters[i].getParameterTypes();
int size;
if ( params[0].equals( Double.TYPE ) || params[0].equals( Long.TYPE ) ) {
size = 3;
@ -313,7 +319,7 @@ class BulkAccessorFactory {
size = 2;
}
code.addInvokeinterface( target_type_index, setters[i].getName(), rawSetterMethod_desc, size );
code.addInvokeinterface( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc, size );
}
}
@ -323,9 +329,9 @@ class BulkAccessorFactory {
code.addOpcode( Opcode.RETURN );
/* current stack len = 0 */
// register in exception table
int throwableType_index = cp.addClassInfo( THROWABLE_CLASS_NAME );
int handler_pc = code.currentPc();
code.addExceptionHandler( start, end, handler_pc, throwableType_index );
final int throwableTypeIndex = constPool.addClassInfo( THROWABLE_CLASS_NAME );
final int handlerPc = code.currentPc();
code.addExceptionHandler( start, end, handlerPc, throwableTypeIndex );
// astore 5 // store exception
code.addAstore( 5 );
// new // BulkAccessorException
@ -337,38 +343,48 @@ class BulkAccessorFactory {
// iload_3 // i
code.addIload( 3 );
// invokespecial // BulkAccessorException.<init>
String cons_desc = "(Ljava/lang/Throwable;I)V";
code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, cons_desc );
final String consDesc = "(Ljava/lang/Throwable;I)V";
code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, consDesc );
// athrow
code.addOpcode( Opcode.ATHROW );
StackMapTable.Writer writer = new StackMapTable.Writer(32);
int[] localTags = { StackMapTable.OBJECT, StackMapTable.OBJECT, StackMapTable.OBJECT, StackMapTable.INTEGER };
int[] localData = { cp.getThisClassInfo(), cp.addClassInfo("java/lang/Object"),
cp.addClassInfo("[Ljava/lang/Object;"), 0};
int[] stackTags = { StackMapTable.OBJECT };
int[] stackData = { throwableType_index };
writer.fullFrame(handler_pc, localTags, localData, stackTags, stackData);
stackmap = writer.toStackMapTable(cp);
final StackMapTable.Writer writer = new StackMapTable.Writer(32);
final int[] localTags = {
StackMapTable.OBJECT,
StackMapTable.OBJECT,
StackMapTable.OBJECT,
StackMapTable.INTEGER
};
final int[] localData = {
constPool.getThisClassInfo(),
constPool.addClassInfo( "java/lang/Object" ),
constPool.addClassInfo( "[Ljava/lang/Object;" ),
0
};
final int[] stackTags = {
StackMapTable.OBJECT
};
final int[] stackData = {
throwableTypeIndex
};
writer.fullFrame( handlerPc, localTags, localData, stackTags, stackData );
stackmap = writer.toStackMapTable( constPool );
}
else {
// return
code.addOpcode( Opcode.RETURN );
}
CodeAttribute ca = code.toCodeAttribute();
if (stackmap != null) {
ca.setAttribute(stackmap);
final CodeAttribute ca = code.toCodeAttribute();
if ( stackmap != null ) {
ca.setAttribute( stackmap );
}
mi.setCodeAttribute( ca );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
setterMethodInfo.setCodeAttribute( ca );
setterMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( setterMethodInfo );
}
private void addUnwrapper(
ClassFile classfile,
Bytecode code,
Class type) {
int index = FactoryHelper.typeIndex( type );
String wrapperType = FactoryHelper.wrapperTypes[index];
private void addUnwrapper(Bytecode code, Class type) {
final int index = FactoryHelper.typeIndex( type );
final String wrapperType = FactoryHelper.wrapperTypes[index];
// checkcast
code.addCheckcast( wrapperType );
// invokevirtual
@ -377,21 +393,21 @@ class BulkAccessorFactory {
private static void findAccessors(
Class clazz,
String[] getterNames,
String[] setterNames,
Class[] types,
Method[] getters,
Method[] setters) {
int length = types.length;
String[] getterNames,
String[] setterNames,
Class[] types,
Method[] getters,
Method[] setters) {
final int length = types.length;
if ( setterNames.length != length || getterNames.length != length ) {
throw new BulkAccessorException( "bad number of accessors" );
}
Class[] getParam = new Class[0];
Class[] setParam = new Class[1];
final Class[] getParam = new Class[0];
final Class[] setParam = new Class[1];
for ( int i = 0; i < length; i++ ) {
if ( getterNames[i] != null ) {
Method getter = findAccessor( clazz, getterNames[i], getParam, i );
final Method getter = findAccessor( clazz, getterNames[i], getParam, i );
if ( getter.getReturnType() != types[i] ) {
throw new BulkAccessorException( "wrong return type: " + getterNames[i], i );
}
@ -406,13 +422,11 @@ class BulkAccessorFactory {
}
}
private static Method findAccessor(
Class clazz,
String name,
Class[] params,
int index) throws BulkAccessorException {
@SuppressWarnings("unchecked")
private static Method findAccessor(Class clazz, String name, Class[] params, int index)
throws BulkAccessorException {
try {
Method method = clazz.getDeclaredMethod( name, params );
final Method method = clazz.getDeclaredMethod( name, params );
if ( Modifier.isPrivate( method.getModifiers() ) ) {
throw new BulkAccessorException( "private property", index );
}

View File

@ -48,8 +48,10 @@ import org.hibernate.internal.util.StringHelper;
* @author Steve Ebersole
*/
public class BytecodeProviderImpl implements BytecodeProvider {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, BytecodeProviderImpl.class.getName());
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
BytecodeProviderImpl.class.getName()
);
@Override
public ProxyFactoryFactory getProxyFactoryFactory() {
@ -59,9 +61,9 @@ public class BytecodeProviderImpl implements BytecodeProvider {
@Override
public ReflectionOptimizer getReflectionOptimizer(
Class clazz,
String[] getterNames,
String[] setterNames,
Class[] types) {
String[] getterNames,
String[] setterNames,
Class[] types) {
FastClass fastClass;
BulkAccessor bulkAccessor;
try {
@ -73,7 +75,7 @@ public class BytecodeProviderImpl implements BytecodeProvider {
}
else {
//test out the optimizer:
Object instance = fastClass.newInstance();
final Object instance = fastClass.newInstance();
bulkAccessor.setPropertyValues( instance, bulkAccessor.getPropertyValues( instance ) );
}
}
@ -81,28 +83,39 @@ public class BytecodeProviderImpl implements BytecodeProvider {
catch ( Throwable t ) {
fastClass = null;
bulkAccessor = null;
if (LOG.isDebugEnabled()) {
int index = 0;
if (t instanceof BulkAccessorException) index = ((BulkAccessorException)t).getIndex();
if (index >= 0) LOG.debugf("Reflection optimizer disabled for: %s [%s: %s (property %s)",
clazz.getName(),
StringHelper.unqualify(t.getClass().getName()),
t.getMessage(),
setterNames[index]);
else LOG.debugf("Reflection optimizer disabled for: %s [%s: %s",
clazz.getName(),
StringHelper.unqualify(t.getClass().getName()),
t.getMessage());
}
if ( LOG.isDebugEnabled() ) {
int index = 0;
if (t instanceof BulkAccessorException) {
index = ( (BulkAccessorException) t ).getIndex();
}
if ( index >= 0 ) {
LOG.debugf(
"Reflection optimizer disabled for %s [%s: %s (property %s)]",
clazz.getName(),
StringHelper.unqualify( t.getClass().getName() ),
t.getMessage(),
setterNames[index]
);
}
else {
LOG.debugf(
"Reflection optimizer disabled for %s [%s: %s]",
clazz.getName(),
StringHelper.unqualify( t.getClass().getName() ),
t.getMessage()
);
}
}
}
if ( fastClass != null && bulkAccessor != null ) {
return new ReflectionOptimizerImpl(
new InstantiationOptimizerAdapter( fastClass ),
new AccessOptimizerAdapter( bulkAccessor, clazz )
new AccessOptimizerAdapter( bulkAccessor, clazz )
);
}
return null;
return null;
}
@Override

View File

@ -30,34 +30,66 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Fast access to class information
*
* @author Muga Nishizawa
*/
public class FastClass implements Serializable {
private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
private Class type;
private final Class type;
private FastClass() {
/**
* Constructs a FastClass
*
* @param type The class to optimize
*
* @return The fast class access to the given class
*/
public static FastClass create(Class type) {
return new FastClass( type );
}
private FastClass(Class type) {
this.type = type;
}
/**
* Access to invoke a method on the class that this fast class handles
*
* @param name The name of the method to invoke,
* @param parameterTypes The method parameter types
* @param obj The instance on which to invoke the method
* @param args The parameter arguments
*
* @return The method result
*
* @throws InvocationTargetException Indicates a problem performing invocation
*/
public Object invoke(
String name,
Class[] parameterTypes,
Object obj,
Object[] args) throws InvocationTargetException {
Class[] parameterTypes,
Object obj,
Object[] args) throws InvocationTargetException {
return this.invoke( this.getIndex( name, parameterTypes ), obj, args );
}
/**
* Access to invoke a method on the class that this fast class handles by its index
*
* @param index The method index
* @param obj The instance on which to invoke the method
* @param args The parameter arguments
*
* @return The method result
*
* @throws InvocationTargetException Indicates a problem performing invocation
*/
public Object invoke(
int index,
Object obj,
Object[] args) throws InvocationTargetException {
Method[] methods = this.type.getMethods();
Object obj,
Object[] args) throws InvocationTargetException {
final Method[] methods = this.type.getMethods();
try {
return methods[index].invoke( obj, args );
}
@ -71,22 +103,49 @@ public class FastClass implements Serializable {
}
}
/**
* Invoke the default constructor
*
* @return The constructed instance
*
* @throws InvocationTargetException Indicates a problem performing invocation
*/
public Object newInstance() throws InvocationTargetException {
return this.newInstance( this.getIndex( EMPTY_CLASS_ARRAY ), null );
}
/**
* Invoke a parameterized constructor
*
* @param parameterTypes The parameter types
* @param args The parameter arguments to pass along
*
* @return The constructed instance
*
* @throws InvocationTargetException Indicates a problem performing invocation
*/
public Object newInstance(
Class[] parameterTypes,
Object[] args) throws InvocationTargetException {
Object[] args) throws InvocationTargetException {
return this.newInstance( this.getIndex( parameterTypes ), args );
}
/**
* Invoke a constructor by its index
*
* @param index The constructor index
* @param args The parameter arguments to pass along
*
* @return The constructed instance
*
* @throws InvocationTargetException Indicates a problem performing invocation
*/
public Object newInstance(
int index,
Object[] args) throws InvocationTargetException {
Constructor[] conss = this.type.getConstructors();
Object[] args) throws InvocationTargetException {
final Constructor[] constructors = this.type.getConstructors();
try {
return conss[index].newInstance( args );
return constructors[index].newInstance( args );
}
catch ( ArrayIndexOutOfBoundsException e ) {
throw new IllegalArgumentException( "Cannot find matching method/constructor" );
@ -99,9 +158,18 @@ public class FastClass implements Serializable {
}
}
/**
* Locate the index of a method
*
* @param name The method name
* @param parameterTypes The method parameter types
*
* @return The index
*/
public int getIndex(String name, Class[] parameterTypes) {
Method[] methods = this.type.getMethods();
boolean eq = true;
final Method[] methods = this.type.getMethods();
boolean eq;
for ( int i = 0; i < methods.length; ++i ) {
if ( !Modifier.isPublic( methods[i].getModifiers() ) ) {
continue;
@ -109,7 +177,7 @@ public class FastClass implements Serializable {
if ( !methods[i].getName().equals( name ) ) {
continue;
}
Class[] params = methods[i].getParameterTypes();
final Class[] params = methods[i].getParameterTypes();
if ( params.length != parameterTypes.length ) {
continue;
}
@ -127,14 +195,22 @@ public class FastClass implements Serializable {
return -1;
}
/**
* Locate the index of a constructor
*
* @param parameterTypes The constructor parameter types
*
* @return The index
*/
public int getIndex(Class[] parameterTypes) {
Constructor[] conss = this.type.getConstructors();
boolean eq = true;
for ( int i = 0; i < conss.length; ++i ) {
if ( !Modifier.isPublic( conss[i].getModifiers() ) ) {
final Constructor[] constructors = this.type.getConstructors();
boolean eq;
for ( int i = 0; i < constructors.length; ++i ) {
if ( !Modifier.isPublic( constructors[i].getModifiers() ) ) {
continue;
}
Class[] params = conss[i].getParameterTypes();
final Class[] params = constructors[i].getParameterTypes();
if ( params.length != parameterTypes.length ) {
continue;
}
@ -152,42 +228,37 @@ public class FastClass implements Serializable {
return -1;
}
public int getMaxIndex() {
Method[] methods = this.type.getMethods();
int count = 0;
for ( int i = 0; i < methods.length; ++i ) {
if ( Modifier.isPublic( methods[i].getModifiers() ) ) {
count++;
}
}
return count;
}
/**
* Get the wrapped class name
*
* @return The class name
*/
public String getName() {
return this.type.getName();
}
/**
* Get the wrapped java class reference
*
* @return The class reference
*/
public Class getJavaClass() {
return this.type;
}
@Override
public String toString() {
return this.type.toString();
}
@Override
public int hashCode() {
return this.type.hashCode();
}
@Override
public boolean equals(Object o) {
if (! ( o instanceof FastClass ) ) {
return false;
}
return this.type.equals( ( ( FastClass ) o ).type );
}
public static FastClass create(Class type) {
FastClass fc = new FastClass( type );
return fc;
return o instanceof FastClass
&& this.type.equals( ((FastClass) o).type );
}
}

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.bytecode.internal.javassist;
/**
* Contract for deciding whether fields should be read and/or write intercepted.
*
@ -34,8 +33,9 @@ public interface FieldFilter {
/**
* Should the given field be read intercepted?
*
* @param desc
* @param name
* @param desc The field descriptor
* @param name The field name
*
* @return true if the given field should be read intercepted; otherwise
* false.
*/
@ -44,14 +44,33 @@ public interface FieldFilter {
/**
* Should the given field be write intercepted?
*
* @param desc
* @param name
* @param desc The field descriptor
* @param name The field name
*
* @return true if the given field should be write intercepted; otherwise
* false.
*/
boolean handleWrite(String desc, String name);
/**
* Should read access to the given field be intercepted?
*
* @param fieldOwnerClassName The class where the field being accessed is defined
* @param fieldName The name of the field being accessed
*
* @return true if the given field read access should be write intercepted; otherwise
* false.
*/
boolean handleReadAccess(String fieldOwnerClassName, String fieldName);
/**
* Should write access to the given field be intercepted?
*
* @param fieldOwnerClassName The class where the field being accessed is defined
* @param fieldName The name of the field being accessed
*
* @return true if the given field write access should be write intercepted; otherwise
* false.
*/
boolean handleWriteAccess(String fieldOwnerClassName, String fieldName);
}

View File

@ -28,52 +28,214 @@ package org.hibernate.bytecode.internal.javassist;
*
* @author Muga Nishizawa
*/
@SuppressWarnings("UnusedDeclaration")
public interface FieldHandler {
/**
* Called to handle writing an int value to a given field.
*
* @param obj ?
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
* @return ?
*
* @return The new value, typically the same as the newValue argument
*/
int writeInt(Object obj, String name, int oldValue, int newValue);
/**
* Called to handle writing a char value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
char writeChar(Object obj, String name, char oldValue, char newValue);
/**
* Called to handle writing a byte value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
byte writeByte(Object obj, String name, byte oldValue, byte newValue);
boolean writeBoolean(Object obj, String name, boolean oldValue,
boolean newValue);
/**
* Called to handle writing a boolean value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue);
/**
* Called to handle writing a short value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
short writeShort(Object obj, String name, short oldValue, short newValue);
/**
* Called to handle writing a float value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
float writeFloat(Object obj, String name, float oldValue, float newValue);
/**
* Called to handle writing a double value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
double writeDouble(Object obj, String name, double oldValue, double newValue);
/**
* Called to handle writing a long value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument
*/
long writeLong(Object obj, String name, long oldValue, long newValue);
/**
* Called to handle writing an Object value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
* @param newValue The new field value.
*
* @return The new value, typically the same as the newValue argument; may be different for entity references
*/
Object writeObject(Object obj, String name, Object oldValue, Object newValue);
/**
* Called to handle reading an int value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
int readInt(Object obj, String name, int oldValue);
/**
* Called to handle reading a char value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
char readChar(Object obj, String name, char oldValue);
/**
* Called to handle reading a byte value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
byte readByte(Object obj, String name, byte oldValue);
/**
* Called to handle reading a boolean value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
boolean readBoolean(Object obj, String name, boolean oldValue);
/**
* Called to handle reading a short value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
short readShort(Object obj, String name, short oldValue);
/**
* Called to handle reading a float value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
float readFloat(Object obj, String name, float oldValue);
/**
* Called to handle reading a double value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
double readDouble(Object obj, String name, double oldValue);
/**
* Called to handle reading a long value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
long readLong(Object obj, String name, long oldValue);
/**
* Called to handle reading an Object value to a given field.
*
* @param obj The object instance on which the write was invoked
* @param name The name of the field being written
* @param oldValue The old field value
*
* @return The field value
*/
Object readObject(Object obj, String name, Object oldValue);
}

View File

@ -37,18 +37,25 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer;
public class InstantiationOptimizerAdapter implements ReflectionOptimizer.InstantiationOptimizer, Serializable {
private final FastClass fastClass;
/**
* Constructs the InstantiationOptimizerAdapter
*
* @param fastClass The fast class for the class to be instantiated here.
*/
public InstantiationOptimizerAdapter(FastClass fastClass) {
this.fastClass = fastClass;
}
@Override
public Object newInstance() {
try {
return fastClass.newInstance();
}
catch ( Throwable t ) {
catch ( Exception e ) {
throw new InstantiationException(
"Could not instantiate entity with Javassist optimizer: ",
fastClass.getJavaClass(), t
fastClass.getJavaClass(),
e
);
}
}

View File

@ -49,10 +49,17 @@ import org.hibernate.internal.CoreMessageLogger;
* @author Dustin Schultz
*/
public class JavassistClassTransformer extends AbstractClassTransformerImpl {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
JavassistClassTransformer.class.getName()
);
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,
JavassistClassTransformer.class.getName());
/**
* Constructs the JavassistClassTransformer
*
* @param classFilter The filter used to determine which classes to transform
* @param fieldFilter The filter used to determine which fields to transform
*/
public JavassistClassTransformer(ClassFilter classFilter, org.hibernate.bytecode.buildtime.spi.FieldFilter fieldFilter) {
super( classFilter, fieldFilter );
}
@ -73,23 +80,27 @@ public class JavassistClassTransformer extends AbstractClassTransformerImpl {
LOG.unableToBuildEnhancementMetamodel( className );
return classfileBuffer;
}
// This is the same as ClassPool.getDefault() but ensures a new ClassPool per
ClassPool cp = new ClassPool();
final ClassPool cp = new ClassPool();
cp.appendSystemPath();
cp.appendClassPath(new ClassClassPath(this.getClass()));
cp.appendClassPath(new ClassClassPath(classfile.getClass()));
cp.appendClassPath( new ClassClassPath( this.getClass() ) );
cp.appendClassPath( new ClassClassPath( classfile.getClass() ) );
try {
cp.makeClassIfNew(new ByteArrayInputStream(classfileBuffer));
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
cp.makeClassIfNew( new ByteArrayInputStream( classfileBuffer ) );
}
FieldTransformer transformer = getFieldTransformer( classfile, cp );
catch (IOException e) {
throw new RuntimeException( e.getMessage(), e );
}
final FieldTransformer transformer = getFieldTransformer( classfile, cp );
if ( transformer != null ) {
LOG.debugf( "Enhancing %s", className );
DataOutputStream out = null;
try {
transformer.transform( classfile );
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
out = new DataOutputStream( byteStream );
classfile.write( out );
return byteStream.toByteArray();
@ -100,7 +111,9 @@ public class JavassistClassTransformer extends AbstractClassTransformerImpl {
}
finally {
try {
if ( out != null ) out.close();
if ( out != null ) {
out.close();
}
}
catch (IOException e) {
//swallow
@ -131,14 +144,15 @@ public class JavassistClassTransformer extends AbstractClassTransformerImpl {
public boolean handleWriteAccess(String fieldOwnerClassName, String fieldName) {
return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName );
}
}, classPool
},
classPool
);
}
private boolean alreadyInstrumented(ClassFile classfile) {
String[] intfs = classfile.getInterfaces();
for ( int i = 0; i < intfs.length; i++ ) {
if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
final String[] interfaces = classfile.getInterfaces();
for ( String anInterface : interfaces ) {
if ( FieldHandled.class.getName().equals( anInterface ) ) {
return true;
}
}

View File

@ -53,6 +53,14 @@ public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
return new JavassistProxyFactory();
}
/**
* Constructs a BasicProxyFactoryImpl
*
* @param superClass The abstract super class (or null if none).
* @param interfaces Interfaces to be proxied (or null if none).
*
* @return The constructed BasicProxyFactoryImpl
*/
public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) {
return new BasicProxyFactoryImpl( superClass, interfaces );
}
@ -64,7 +72,8 @@ public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) {
throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" );
}
javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
final javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
factory.setFilter( FINALIZE_FILTER );
if ( superClass != null ) {
factory.setSuperclass( superClass );
@ -77,7 +86,7 @@ public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
public Object getProxy() {
try {
ProxyObject proxy = ( ProxyObject ) proxyClass.newInstance();
final ProxyObject proxy = (ProxyObject) proxyClass.newInstance();
proxy.setHandler( new PassThroughHandler( proxy, proxyClass.getName() ) );
return proxy;
}
@ -108,12 +117,13 @@ public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
this.proxiedClassName = proxiedClassName;
}
@SuppressWarnings("unchecked")
public Object invoke(
Object object,
Method method,
Method method1,
Object[] args) throws Exception {
String name = method.getName();
Method method,
Method method1,
Object[] args) throws Exception {
final String name = method.getName();
if ( "toString".equals( name ) ) {
return proxiedClassName + "@" + System.identityHashCode( object );
}
@ -123,18 +133,22 @@ public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
else if ( "hashCode".equals( name ) ) {
return System.identityHashCode( object );
}
boolean hasGetterSignature = method.getParameterTypes().length == 0 && method.getReturnType() != null;
boolean hasSetterSignature = method.getParameterTypes().length == 1 && ( method.getReturnType() == null || method.getReturnType() == void.class );
final boolean hasGetterSignature = method.getParameterTypes().length == 0
&& method.getReturnType() != null;
final boolean hasSetterSignature = method.getParameterTypes().length == 1
&& ( method.getReturnType() == null || method.getReturnType() == void.class );
if ( name.startsWith( "get" ) && hasGetterSignature ) {
String propName = name.substring( 3 );
final String propName = name.substring( 3 );
return data.get( propName );
}
else if ( name.startsWith( "is" ) && hasGetterSignature ) {
String propName = name.substring( 2 );
final String propName = name.substring( 2 );
return data.get( propName );
}
else if ( name.startsWith( "set" ) && hasSetterSignature) {
String propName = name.substring( 3 );
final String propName = name.substring( 3 );
data.put( propName, args[0] );
return null;
}

View File

@ -33,21 +33,28 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer;
* @author Steve Ebersole
*/
public class ReflectionOptimizerImpl implements ReflectionOptimizer, Serializable {
private final InstantiationOptimizer instantiationOptimizer;
private final AccessOptimizer accessOptimizer;
/**
* Constructs a ReflectionOptimizerImpl
*
* @param instantiationOptimizer The instantiation optimizer to use
* @param accessOptimizer The property access optimizer to use.
*/
public ReflectionOptimizerImpl(
InstantiationOptimizer instantiationOptimizer,
AccessOptimizer accessOptimizer) {
AccessOptimizer accessOptimizer) {
this.instantiationOptimizer = instantiationOptimizer;
this.accessOptimizer = accessOptimizer;
}
@Override
public InstantiationOptimizer getInstantiationOptimizer() {
return instantiationOptimizer;
}
@Override
public AccessOptimizer getAccessOptimizer() {
return accessOptimizer;
}

View File

@ -33,46 +33,53 @@ import javassist.NotFoundException;
import org.hibernate.HibernateException;
/**
* A ClassLoader implementation applying Class transformations as they are being loaded.
*
* @author Steve Ebersole
*/
@SuppressWarnings("UnusedDeclaration")
public class TransformingClassLoader extends ClassLoader {
private ClassLoader parent;
private ClassPool classPool;
/*package*/ TransformingClassLoader(ClassLoader parent, String[] classpath) {
TransformingClassLoader(ClassLoader parent, String[] classpaths) {
this.parent = parent;
classPool = new ClassPool( true );
for ( int i = 0; i < classpath.length; i++ ) {
this.classPool = new ClassPool( true );
for ( String classpath : classpaths ) {
try {
classPool.appendClassPath( classpath[i] );
classPool.appendClassPath( classpath );
}
catch ( NotFoundException e ) {
catch (NotFoundException e) {
throw new HibernateException(
"Unable to resolve requested classpath for transformation [" +
classpath[i] + "] : " + e.getMessage()
classpath + "] : " + e.getMessage()
);
}
}
}
@Override
protected Class findClass(String name) throws ClassNotFoundException {
try {
CtClass cc = classPool.get( name );
// todo : modify the class definition if not already transformed...
byte[] b = cc.toBytecode();
return defineClass( name, b, 0, b.length );
}
catch ( NotFoundException e ) {
throw new ClassNotFoundException();
}
catch ( IOException e ) {
throw new ClassNotFoundException();
}
catch ( CannotCompileException e ) {
throw new ClassNotFoundException();
}
}
try {
final CtClass cc = classPool.get( name );
// todo : modify the class definition if not already transformed...
byte[] b = cc.toBytecode();
return defineClass( name, b, 0, b.length );
}
catch (NotFoundException e) {
throw new ClassNotFoundException();
}
catch (IOException e) {
throw new ClassNotFoundException();
}
catch (CannotCompileException e) {
throw new ClassNotFoundException();
}
}
/**
* Used to release resources. Call when done with the ClassLoader
*/
public void release() {
classPool = null;
parent = null;

View File

@ -0,0 +1,4 @@
/**
* Javassist support internals
*/
package org.hibernate.bytecode.internal.javassist;

View File

@ -35,7 +35,6 @@ import org.hibernate.bytecode.buildtime.spi.FieldFilter;
* @author Steve Ebersole
*/
public abstract class AbstractClassTransformerImpl implements ClassTransformer {
protected final ClassFilter classFilter;
protected final FieldFilter fieldFilter;
@ -44,6 +43,7 @@ public abstract class AbstractClassTransformerImpl implements ClassTransformer {
this.fieldFilter = fieldFilter;
}
@Override
public byte[] transform(
ClassLoader loader,
String className,
@ -60,6 +60,17 @@ public abstract class AbstractClassTransformerImpl implements ClassTransformer {
}
}
/**
* Delegate the transformation call from {@link #transform}
*
* @param loader The class loader to use
* @param className The name of the class to transform
* @param classBeingRedefined If an already loaded class is being redefined, then pass this as a parameter
* @param protectionDomain The protection domain of the class being (re)defined
* @param classfileBuffer The bytes of the class file.
*
* @return The transformed (enhanced/instrumented) bytes.
*/
protected abstract byte[] doTransform(
ClassLoader loader,
String className,

View File

@ -24,13 +24,13 @@
package org.hibernate.bytecode.spi;
/**
* A proxy factory for "basic proxy" generation
* A proxy factory for "basic proxy" generation.
*
* @author Steve Ebersole
*/
public interface BasicProxyFactory {
/**
* Get a proxy reference.
* Get a proxy reference..
*
* @return A proxy reference.
*/

View File

@ -37,12 +37,15 @@ import java.util.zip.ZipInputStream;
* @author Steve Ebersole
*/
public class ByteCodeHelper {
/**
* Disallow instantiation (its a helper)
*/
private ByteCodeHelper() {
}
/**
* Reads class byte array info from the given input stream.
* <p/>
*
* The stream is closed within this method!
*
* @param inputStream The stream containing the class binary; null will lead to an {@link IOException}
@ -56,13 +59,13 @@ public class ByteCodeHelper {
throw new IOException( "null input stream" );
}
byte[] buffer = new byte[409600];
final byte[] buffer = new byte[409600];
byte[] classBytes = new byte[0];
try {
int r = inputStream.read( buffer );
while ( r >= buffer.length ) {
byte[] temp = new byte[ classBytes.length + buffer.length ];
final byte[] temp = new byte[ classBytes.length + buffer.length ];
// copy any previously read bytes into the temp array
System.arraycopy( classBytes, 0, temp, 0, classBytes.length );
// copy the just read bytes into the temp array (after the previously read)
@ -72,7 +75,7 @@ public class ByteCodeHelper {
r = inputStream.read( buffer );
}
if ( r != -1 ) {
byte[] temp = new byte[ classBytes.length + r ];
final byte[] temp = new byte[ classBytes.length + r ];
// copy any previously read bytes into the temp array
System.arraycopy( classBytes, 0, temp, 0, classBytes.length );
// copy the just read bytes into the temp array (after the previously read)
@ -109,18 +112,18 @@ public class ByteCodeHelper {
* Read class definition a zip (jar) file entry.
*
* @param zip The zip entry stream.
*
*
* @return The class bytes
*
* @throws IOException Indicates a problem accessing the given stream.
*/
public static byte[] readByteCode(ZipInputStream zip) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
InputStream in = new BufferedInputStream( zip );
int b;
while ( ( b = in.read() ) != -1 ) {
bout.write( b );
}
return bout.toByteArray();
}
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final InputStream in = new BufferedInputStream( zip );
int b;
while ( ( b = in.read() ) != -1 ) {
bout.write( b );
}
return bout.toByteArray();
}
}

View File

@ -32,25 +32,24 @@ import java.security.ProtectionDomain;
* entity class files when they are loaded and redefined. The transformation
* occurs before the class is defined by the JVM
*
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @author Emmanuel Bernard
*/
public interface ClassTransformer
{
/**
* Invoked when a class is being loaded or redefined to add hooks for persistence bytecode manipulation
*
* @param loader the defining class loaderof the class being transformed. It may be null if using bootstrap loader
* @param classname The name of the class being transformed
* @param classBeingRedefined If an already loaded class is being redefined, then pass this as a parameter
* @param protectionDomain ProtectionDomain of the class being (re)-defined
* @param classfileBuffer The input byte buffer in class file format
* @return A well-formed class file that can be loaded
*/
public byte[] transform(ClassLoader loader,
String classname,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer);
public interface ClassTransformer {
/**
* Invoked when a class is being loaded or redefined to add hooks for persistence bytecode manipulation.
*
* @param loader the defining class loaderof the class being transformed. It may be null if using bootstrap loader
* @param classname The name of the class being transformed
* @param classBeingRedefined If an already loaded class is being redefined, then pass this as a parameter
* @param protectionDomain ProtectionDomain of the class being (re)-defined
* @param classfileBuffer The input byte buffer in class file format
* @return A well-formed class file that can be loaded
*/
public byte[] transform(
ClassLoader loader,
String classname,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer);
}

View File

@ -42,15 +42,15 @@ public interface EntityInstrumentationMetadata {
public String getEntityName();
/**
* Has the entity class been bytecode instrumented?
* Has the entity class been bytecode instrumented?
*
* @return {@code true} indicates the entity class is instrumented for Hibernate use; {@code false}
* indicates it is not
*/
public boolean isInstrumented();
public boolean isInstrumented();
/**
* Build and inject a field interceptor instance into the instrumented entity.
/**
* Build and inject a field interceptor instance into the instrumented entity.
*
* @param entity The entity into which built interceptor should be injected
* @param entityName The name of the entity
@ -60,15 +60,15 @@ public interface EntityInstrumentationMetadata {
* @return The built and injected interceptor
*
* @throws NotInstrumentedException Thrown if {@link #isInstrumented()} returns {@code false}
*/
public FieldInterceptor injectInterceptor(
Object entity,
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) throws NotInstrumentedException;
*/
public FieldInterceptor injectInterceptor(
Object entity,
String entityName,
Set uninitializedFieldNames,
SessionImplementor session) throws NotInstrumentedException;
/**
* Extract the field interceptor instance from the instrumented entity.
/**
* Extract the field interceptor instance from the instrumented entity.
*
* @param entity The entity from which to extract the interceptor
*
@ -76,5 +76,5 @@ public interface EntityInstrumentationMetadata {
*
* @throws NotInstrumentedException Thrown if {@link #isInstrumented()} returns {@code false}
*/
public FieldInterceptor extractInterceptor(Object entity) throws NotInstrumentedException;
public FieldInterceptor extractInterceptor(Object entity) throws NotInstrumentedException;
}

View File

@ -26,39 +26,45 @@ package org.hibernate.bytecode.spi;
import java.io.InputStream;
/**
* A specialized classloader which performs bytecode enhancement on class
* definitions as they are loaded into the classloader scope.
* A specialized ClassLoader which performs bytecode enhancement on class definitions as they are loaded
* into the ClassLoader scope.
*
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
public class InstrumentedClassLoader extends ClassLoader {
private final ClassTransformer classTransformer;
private ClassTransformer classTransformer;
/**
* Constructs an InstrumentedClassLoader.
*
* @param parent The parent ClassLoader
* @param classTransformer The transformer to use for applying enhancement
*/
public InstrumentedClassLoader(ClassLoader parent, ClassTransformer classTransformer) {
super( parent );
this.classTransformer = classTransformer;
}
@Override
public Class loadClass(String name) throws ClassNotFoundException {
if ( name.startsWith( "java." ) || classTransformer == null ) {
return getParent().loadClass( name );
}
Class c = findLoadedClass( name );
final Class c = findLoadedClass( name );
if ( c != null ) {
return c;
}
InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" );
final InputStream is = this.getResourceAsStream( name.replace( '.', '/' ) + ".class" );
if ( is == null ) {
throw new ClassNotFoundException( name + " not found" );
}
try {
byte[] originalBytecode = ByteCodeHelper.readByteCode( is );
byte[] transformedBytecode = classTransformer.transform( getParent(), name, null, null, originalBytecode );
final byte[] originalBytecode = ByteCodeHelper.readByteCode( is );
final byte[] transformedBytecode = classTransformer.transform( getParent(), name, null, null, originalBytecode );
if ( originalBytecode == transformedBytecode ) {
// no transformations took place, so handle it as we would a
// non-instrumented class

View File

@ -26,14 +26,18 @@ package org.hibernate.bytecode.spi;
import org.hibernate.HibernateException;
/**
* Indicates a condition where an instrumented/enhanced class was expected, but the class was not
* instrumented/enhanced.
*
* @author Steve Ebersole
*/
public class NotInstrumentedException extends HibernateException {
/**
* Constructs a NotInstrumentedException
*
* @param message Message explaining the exception condition
*/
public NotInstrumentedException(String message) {
super( message );
}
public NotInstrumentedException(String message, Throwable root) {
super( message, root );
}
}

View File

@ -29,8 +29,18 @@ package org.hibernate.bytecode.spi;
* @author Steve Ebersole
*/
public interface ReflectionOptimizer {
/**
* Retrieve the optimizer for calling an entity's constructor via reflection.
*
* @return The optimizer for instantiation
*/
public InstantiationOptimizer getInstantiationOptimizer();
/**
* Retrieve the optimizer for accessing the entity's persistent state.
*
* @return The optimizer for persistent state access
*/
public AccessOptimizer getAccessOptimizer();
/**
@ -51,8 +61,28 @@ public interface ReflectionOptimizer {
* @author Steve Ebersole
*/
public interface AccessOptimizer {
/**
* Get the name of all properties.
*
* @return The name of all properties.
*/
public String[] getPropertyNames();
/**
* Get the value of all properties from the given entity
*
* @param object The entity from which to extract values.
*
* @return The values.
*/
public Object[] getPropertyValues(Object object);
/**
* Set all property values into an entity instance.
*
* @param object The entity instance
* @param values The values to inject
*/
public void setPropertyValues(Object object, Object[] values);
}
}

View File

@ -0,0 +1,4 @@
/**
* Package defining bytecode code enhancement (instrumentation) support.
*/
package org.hibernate.bytecode.spi;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, 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 Middleware LLC.
* 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
@ -20,26 +20,41 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.cache;
import org.hibernate.HibernateException;
/**
* Something went wrong in the cache
*/
public class CacheException extends HibernateException {
public CacheException(String s) {
super(s);
/**
* Constructs a CacheException.
*
* @param message Message explaining the exception condition
*/
public CacheException(String message) {
super( message );
}
public CacheException(String s, Throwable e) {
super(s, e);
/**
* Constructs a CacheException.
*
* @param message Message explaining the exception condition
* @param cause The underlying cause
*/
public CacheException(String message, Throwable cause) {
super( message, cause );
}
public CacheException(Throwable e) {
super(e);
/**
* Constructs a CacheException.
*
* @param cause The underlying cause
*/
public CacheException(Throwable cause) {
super( cause );
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2008, 2013, 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 Middleware LLC.
* 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
@ -20,21 +20,30 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.cache;
import org.hibernate.cfg.Environment;
/**
* Implementation of NoCacheRegionFactoryAvailableException.
* Indicates a condition where a second-level cache implementation was expected to be to available, but
* none was found on the classpath.
*
* @author Steve Ebersole
*/
public class NoCacheRegionFactoryAvailableException extends CacheException {
private static final String MSG = "Second-level cache is used in the application, but property "
+ Environment.CACHE_REGION_FACTORY + " is not given, please either disable second level cache" +
" or set correct region factory class name to property "+Environment.CACHE_REGION_FACTORY+
" (and make sure the second level cache provider, hibernate-infinispan, for example, is available in the classpath).";
private static final String MSG = String.format(
"Second-level cache is used in the application, but property %s is not given; " +
"please either disable second level cache or set correct region factory using the %s setting " +
"and make sure the second level cache provider (hibernate-infinispan, e.g.) is available on the " +
"classpath.",
Environment.CACHE_REGION_FACTORY,
Environment.CACHE_REGION_FACTORY
);
/**
* Constructs a NoCacheRegionFactoryAvailableException with a standard message.
*/
public NoCacheRegionFactoryAvailableException() {
super( MSG );
}

View File

@ -24,6 +24,8 @@
package org.hibernate.cache;
/**
* Legacy (deprecated) namespace for the RegionFactory contract.
*
* @author Steve Ebersole
*
* @deprecated Moved, but still need this definition for ehcache

View File

@ -97,10 +97,10 @@ public class CacheKey implements Serializable {
//hashCode is part of this check since it is pre-calculated and hash must match for equals to be true
return false;
}
CacheKey that = (CacheKey) other;
return EqualsHelper.equals( entityOrRoleName, that.entityOrRoleName ) &&
type.isEqual( key, that.key ) &&
EqualsHelper.equals( tenantId, that.tenantId );
final CacheKey that = (CacheKey) other;
return EqualsHelper.equals( entityOrRoleName, that.entityOrRoleName )
&& type.isEqual( key, that.key )
&& EqualsHelper.equals( tenantId, that.tenantId );
}
@Override
@ -111,6 +111,6 @@ public class CacheKey implements Serializable {
@Override
public String toString() {
// Used to be required for OSCache
return entityOrRoleName + '#' + key.toString();//"CacheKey#" + type.toString(key, sf);
return entityOrRoleName + '#' + key.toString();
}
}

View File

@ -40,43 +40,55 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public final class FilterKey implements Serializable {
private String filterName;
private Map<String,TypedValue> filterParameters = new HashMap<String,TypedValue>();
public FilterKey(String name, Map<String,?> params, Map<String,Type> types) {
private final String filterName;
private final Map<String,TypedValue> filterParameters = new HashMap<String,TypedValue>();
FilterKey(String name, Map<String,?> params, Map<String,Type> types) {
filterName = name;
for ( Map.Entry<String, ?> paramEntry : params.entrySet() ) {
Type type = types.get( paramEntry.getKey() );
final Type type = types.get( paramEntry.getKey() );
filterParameters.put( paramEntry.getKey(), new TypedValue( type, paramEntry.getValue() ) );
}
}
@Override
public int hashCode() {
int result = 13;
result = 37 * result + filterName.hashCode();
result = 37 * result + filterParameters.hashCode();
return result;
}
@Override
public boolean equals(Object other) {
if ( !(other instanceof FilterKey) ) return false;
FilterKey that = (FilterKey) other;
if ( !that.filterName.equals(filterName) ) return false;
if ( !that.filterParameters.equals(filterParameters) ) return false;
return true;
if ( !(other instanceof FilterKey) ) {
return false;
}
final FilterKey that = (FilterKey) other;
return that.filterName.equals( filterName )
&& that.filterParameters.equals( filterParameters );
}
@Override
public String toString() {
return "FilterKey[" + filterName + filterParameters + ']';
}
/**
* Constructs a number of FilterKey instances, given the currently enabled filters
*
* @param enabledFilters The currently enabled filters
*
* @return The filter keys, one per enabled filter
*/
public static Set<FilterKey> createFilterKeys(Map<String,Filter> enabledFilters) {
if ( enabledFilters.size()==0 ) {
if ( enabledFilters.size() == 0 ) {
return null;
}
Set<FilterKey> result = new HashSet<FilterKey>();
final Set<FilterKey> result = new HashSet<FilterKey>();
for ( Filter filter : enabledFilters.values() ) {
FilterKey key = new FilterKey(
final FilterKey key = new FilterKey(
filter.getName(),
( (FilterImpl) filter ).getParameters(),
filter.getFilterDefinition().getParameterTypes()

View File

@ -76,38 +76,38 @@ public class NaturalIdCacheKey implements Serializable {
result = prime * result + ( ( this.tenantId == null ) ? 0 : this.tenantId.hashCode() );
for ( int i = 0; i < naturalIdValues.length; i++ ) {
final int naturalIdPropertyIndex = naturalIdPropertyIndexes[i];
final Type type = propertyTypes[naturalIdPropertyIndex];
final Type type = propertyTypes[naturalIdPropertyIndex];
final Object value = naturalIdValues[i];
result = prime * result + (value != null ? type.getHashCode( value, factory ) : 0);
this.naturalIdValues[i] = type.disassemble( value, session, null );
}
this.hashCode = result;
initTransients();
}
private void initTransients() {
this.toString = new ValueHolder<String>(
new ValueHolder.DeferredInitializer<String>() {
@Override
public String initialize() {
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
//the only same way to differentiate the keys is to included the disassembled values in the string.
final StringBuilder toStringBuilder = new StringBuilder( entityName ).append( "##NaturalId[" );
for ( int i = 0; i < naturalIdValues.length; i++ ) {
toStringBuilder.append( naturalIdValues[i] );
if ( i + 1 < naturalIdValues.length ) {
toStringBuilder.append( ", " );
}
}
toStringBuilder.append( "]" );
return toStringBuilder.toString();
}
}
);
private void initTransients() {
this.toString = new ValueHolder<String>(
new ValueHolder.DeferredInitializer<String>() {
@Override
public String initialize() {
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
//the only same way to differentiate the keys is to included the disassembled values in the string.
final StringBuilder toStringBuilder = new StringBuilder( entityName ).append( "##NaturalId[" );
for ( int i = 0; i < naturalIdValues.length; i++ ) {
toStringBuilder.append( naturalIdValues[i] );
if ( i + 1 < naturalIdValues.length ) {
toStringBuilder.append( ", " );
}
}
toStringBuilder.append( "]" );
return toStringBuilder.toString();
}
}
);
}
@SuppressWarnings( {"UnusedDeclaration"})
@ -129,7 +129,7 @@ public class NaturalIdCacheKey implements Serializable {
public String toString() {
return toString.getValue();
}
@Override
public int hashCode() {
return this.hashCode;
@ -154,10 +154,10 @@ public class NaturalIdCacheKey implements Serializable {
&& EqualsHelper.equals( tenantId, other.tenantId )
&& Arrays.deepEquals( this.naturalIdValues, other.naturalIdValues );
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
ois.defaultReadObject();
initTransients();
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
ois.defaultReadObject();
initTransients();
}
}

View File

@ -40,15 +40,53 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public interface QueryCache {
/**
* Clear items from the query cache.
*
* @throws CacheException Indicates a problem delegating to the underlying cache.
*/
public void clear() throws CacheException;
/**
* Put a result into the query cache.
*
* @param key The cache key
* @param returnTypes The result types
* @param result The results to cache
* @param isNaturalKeyLookup Was this a natural id lookup?
* @param session The originating session
*
* @return Whether the put actually happened.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
public boolean put(QueryKey key, Type[] returnTypes, List result, boolean isNaturalKeyLookup, SessionImplementor session) throws HibernateException;
/**
* Get results from the cache.
*
* @param key The cache key
* @param returnTypes The result types
* @param isNaturalKeyLookup Was this a natural id lookup?
* @param spaces The query spaces (used in invalidation plus validation checks)
* @param session The originating session
*
* @return The cached results; may be null.
*
* @throws HibernateException Indicates a problem delegating to the underlying cache.
*/
public List get(QueryKey key, Type[] returnTypes, boolean isNaturalKeyLookup, Set spaces, SessionImplementor session) throws HibernateException;
/**
* Destroy the cache.
*/
public void destroy();
/**
* The underlying cache factory region being used.
*
* @return The cache region.
*/
public QueryResultsRegion getRegion();
}

Some files were not shown because too many files have changed in this diff Show More