HHH-8159 - Apply fixups indicated by analysis tools
This commit is contained in:
parent
bca73db4f9
commit
6a388b754c
16
build.gradle
16
build.gradle
|
@ -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
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}.
|
||||
*
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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() )
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 + ">";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internals for action processing.
|
||||
*/
|
||||
package org.hibernate.action.internal;
|
|
@ -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";
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* The class loading service internals.
|
||||
*/
|
||||
package org.hibernate.boot.registry.classloading.internal;
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* The internals for building service registries.
|
||||
*/
|
||||
package org.hibernate.boot.registry.internal;
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internals for building StrategySelector
|
||||
*/
|
||||
package org.hibernate.boot.registry.selector.internal;
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Javassist support internals
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.internal;
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ) ||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Package defining bytecode code enhancement (instrumentation) support.
|
||||
*/
|
||||
package org.hibernate.bytecode.enhance;
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Package defining bytecode code enhancement (instrumentation) support.
|
||||
*/
|
||||
package org.hibernate.bytecode.enhance.spi;
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() +
|
||||
')';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Javassist support internals
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal.javassist;
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Bytecode instrumentation internals
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal;
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Javassist support internals
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Package defining bytecode code enhancement (instrumentation) support.
|
||||
*/
|
||||
package org.hibernate.bytecode.spi;
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue