HHH-10280 - Remove legacy bytecode enhancement artifacts
This commit is contained in:
parent
c0528b7079
commit
472f4ab9ef
|
@ -8,9 +8,7 @@ package org.hibernate;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.HibernateIterator;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
|
@ -174,16 +172,11 @@ public final class Hibernate {
|
|||
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoader ) {
|
||||
return ( (LazyAttributeLoader) interceptor ).isAttributeLoaded( propertyName );
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
return ( (LazyAttributeLoadingInterceptor) interceptor ).isAttributeLoaded( propertyName );
|
||||
}
|
||||
}
|
||||
|
||||
if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
|
||||
final FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( entity );
|
||||
return interceptor == null || interceptor.isInitialized( propertyName );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.internal;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import javassist.bytecode.ClassFile;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.spi.AbstractInstrumenter;
|
||||
import org.hibernate.bytecode.buildtime.spi.BasicClassFilter;
|
||||
import org.hibernate.bytecode.buildtime.spi.ClassDescriptor;
|
||||
import org.hibernate.bytecode.buildtime.spi.Logger;
|
||||
import org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl;
|
||||
import org.hibernate.bytecode.internal.javassist.FieldHandled;
|
||||
import org.hibernate.bytecode.spi.ClassTransformer;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
|
||||
/**
|
||||
* Strategy for performing build-time instrumentation of persistent classes in order to enable
|
||||
* field-level interception using Javassist.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Muga Nishizawa
|
||||
*/
|
||||
public class JavassistInstrumenter extends AbstractInstrumenter {
|
||||
|
||||
private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
|
||||
|
||||
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 );
|
||||
DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedBytecodeEnhancement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
|
||||
return new CustomClassDescriptor( bytecode );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames) {
|
||||
if ( descriptor.isInstrumented() ) {
|
||||
logger.debug( "class [" + descriptor.getName() + "] already instrumented" );
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor, classNames ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomClassDescriptor implements ClassDescriptor {
|
||||
private final byte[] bytes;
|
||||
private final ClassFile classFile;
|
||||
|
||||
public CustomClassDescriptor(byte[] bytes) throws IOException {
|
||||
this.bytes = bytes;
|
||||
this.classFile = new ClassFile( new DataInputStream( new ByteArrayInputStream( bytes ) ) );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return classFile.getName();
|
||||
}
|
||||
|
||||
public boolean isInstrumented() {
|
||||
final String[] interfaceNames = classFile.getInterfaces();
|
||||
for ( String interfaceName : interfaceNames ) {
|
||||
if ( FieldHandled.class.getName().equals( interfaceName ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Javassist support internals
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.internal;
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.hibernate.bytecode.spi.ByteCodeHelper;
|
||||
import org.hibernate.bytecode.spi.ClassTransformer;
|
||||
|
||||
/**
|
||||
* Provides the basic templating of how instrumentation should occur.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates the basic instrumentation strategy.
|
||||
*
|
||||
* @param logger The bridge to the environment's logging system.
|
||||
* @param options User-supplied options.
|
||||
*/
|
||||
public AbstractInstrumenter(Logger logger, Options options) {
|
||||
this.logger = logger;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the bytecode of a java class, retrieve the descriptor for that class.
|
||||
*
|
||||
* @param byecode The class bytecode.
|
||||
*
|
||||
* @return The class's descriptor
|
||||
*
|
||||
* @throws Exception Indicates problems access the bytecode.
|
||||
*/
|
||||
protected abstract ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception;
|
||||
|
||||
/**
|
||||
* Create class transformer for the class.
|
||||
*
|
||||
* @param descriptor The descriptor of the class to be instrumented.
|
||||
* @param classNames The names of all classes to be instrumented; the "pipeline" if you will.
|
||||
*
|
||||
* @return The transformer for the given class; may return null to indicate that transformation should
|
||||
* be skipped (ala already instrumented).
|
||||
*/
|
||||
protected abstract ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames);
|
||||
|
||||
/**
|
||||
* The main instrumentation entry point. Given a set of files, perform instrumentation on each discovered class
|
||||
* file.
|
||||
*
|
||||
* @param files The files.
|
||||
*/
|
||||
public void execute(Set<File> files) {
|
||||
final Set<String> classNames = new HashSet<String>();
|
||||
|
||||
if ( options.performExtendedInstrumentation() ) {
|
||||
logger.debug( "collecting class names for extended instrumentation determination" );
|
||||
try {
|
||||
for ( Object file1 : files ) {
|
||||
final File file = (File) file1;
|
||||
collectClassNames( file, classNames );
|
||||
}
|
||||
}
|
||||
catch ( ExecutionException ee ) {
|
||||
throw ee;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new ExecutionException( e );
|
||||
}
|
||||
}
|
||||
|
||||
logger.info( "starting instrumentation" );
|
||||
try {
|
||||
for ( File file : files ) {
|
||||
processFile( file, classNames );
|
||||
}
|
||||
}
|
||||
catch ( ExecutionException ee ) {
|
||||
throw ee;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new ExecutionException( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the names of classes from file, adding them to the classNames collection.
|
||||
* <p/>
|
||||
* IMPL NOTE : file here may be either a class file or a jar. If a jar, all entries in the jar file are
|
||||
* processed.
|
||||
*
|
||||
* @param file The file from which to extract class metadata (descriptor).
|
||||
* @param classNames The collected class name collection.
|
||||
*
|
||||
* @throws Exception indicates problems accessing the file or its contents.
|
||||
*/
|
||||
private void collectClassNames(File file, final Set<String> classNames) 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
|
||||
final DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
|
||||
if ( din.readInt() == CLASS_MAGIC ) {
|
||||
classNames.add( getClassDescriptor( byteCode ).getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
final ZipFileProcessor processor = new ZipFileProcessor( collector );
|
||||
processor.process( file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this file represent a compiled class?
|
||||
*
|
||||
* @param file The file to check.
|
||||
*
|
||||
* @return True if the file is a class; false otherwise.
|
||||
*
|
||||
* @throws IOException Indicates problem access the file.
|
||||
*/
|
||||
protected final boolean isClassFile(File file) throws IOException {
|
||||
return checkMagic( file, CLASS_MAGIC );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this file represent a zip file of some format?
|
||||
*
|
||||
* @param file The file to check.
|
||||
*
|
||||
* @return True if the file is n archive; false otherwise.
|
||||
*
|
||||
* @throws IOException Indicates problem access the file.
|
||||
*/
|
||||
protected final boolean isJarFile(File file) throws IOException {
|
||||
return checkMagic( file, ZIP_MAGIC );
|
||||
}
|
||||
|
||||
protected final boolean checkMagic(File file, long magic) throws IOException {
|
||||
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.
|
||||
* <p/>
|
||||
* Again, just like with {@link #collectClassNames} this method can handle both class and archive files.
|
||||
*
|
||||
* @param file The file to process.
|
||||
* @param classNames The 'pipeline' of classes to be processed. Only actually populated when the user
|
||||
* specifies to perform {@link org.hibernate.bytecode.buildtime.spi.Instrumenter.Options#performExtendedInstrumentation() extended} instrumentation.
|
||||
*
|
||||
* @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 ) ) {
|
||||
logger.debug( "processing class file : " + file.getAbsolutePath() );
|
||||
processClassFile( file, classNames );
|
||||
}
|
||||
else if ( isJarFile( file ) ) {
|
||||
logger.debug( "processing jar file : " + file.getAbsolutePath() );
|
||||
processJarFile( file, classNames );
|
||||
}
|
||||
else {
|
||||
logger.debug( "ignoring file : " + file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a class file. Delegated to from {@link #processFile} in the case of a class file.
|
||||
*
|
||||
* @param file The class file to process.
|
||||
* @param classNames The 'pipeline' of classes to be processed. Only actually populated when the user
|
||||
* specifies to perform {@link org.hibernate.bytecode.buildtime.spi.Instrumenter.Options#performExtendedInstrumentation() extended} instrumentation.
|
||||
*
|
||||
* @throws Exception Indicates an issue either access files or applying the transformations.
|
||||
*/
|
||||
protected void processClassFile(File file, Set<String> classNames) throws Exception {
|
||||
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() );
|
||||
final byte[] transformedBytes = transformer.transform(
|
||||
getClass().getClassLoader(),
|
||||
descriptor.getName(),
|
||||
null,
|
||||
null,
|
||||
descriptor.getBytes()
|
||||
);
|
||||
|
||||
final OutputStream out = new FileOutputStream( file );
|
||||
try {
|
||||
out.write( transformedBytes );
|
||||
out.flush();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
out.close();
|
||||
}
|
||||
catch ( IOException ignore) {
|
||||
// intentionally empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an archive file. Delegated to from {@link #processFile} in the case of an archive file.
|
||||
*
|
||||
* @param file The archive file to process.
|
||||
* @param classNames The 'pipeline' of classes to be processed. Only actually populated when the user
|
||||
* specifies to perform {@link org.hibernate.bytecode.buildtime.spi.Instrumenter.Options#performExtendedInstrumentation() extended} instrumentation.
|
||||
*
|
||||
* @throws Exception Indicates an issue either access files or applying the transformations.
|
||||
*/
|
||||
protected void processJarFile(final File file, final Set<String> classNames) throws Exception {
|
||||
final File tempFile = File.createTempFile(
|
||||
file.getName(),
|
||||
null,
|
||||
new File( file.getAbsoluteFile().getParent() )
|
||||
);
|
||||
|
||||
try {
|
||||
final FileOutputStream fout = new FileOutputStream( tempFile, false );
|
||||
try {
|
||||
final ZipOutputStream out = new ZipOutputStream( fout );
|
||||
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
|
||||
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() );
|
||||
}
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
final ZipFileProcessor processor = new ZipFileProcessor( transformer );
|
||||
processor.process( file );
|
||||
out.close();
|
||||
}
|
||||
finally{
|
||||
fout.close();
|
||||
}
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows control over what exactly to transform.
|
||||
*/
|
||||
protected class CustomFieldFilter implements FieldFilter {
|
||||
private final ClassDescriptor descriptor;
|
||||
private final Set classNames;
|
||||
|
||||
public CustomFieldFilter(ClassDescriptor descriptor, Set classNames) {
|
||||
this.descriptor = descriptor;
|
||||
this.classNames = classNames;
|
||||
}
|
||||
|
||||
public boolean shouldInstrumentField(String className, String fieldName) {
|
||||
if ( descriptor.getName().equals( className ) ) {
|
||||
logger.trace( "accepting transformation of field [" + className + "." + fieldName + "]" );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.trace( "rejecting transformation of field [" + className + "." + fieldName + "]" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldTransformFieldAccess(
|
||||
String transformingClassName,
|
||||
String fieldOwnerClassName,
|
||||
String fieldName) {
|
||||
if ( descriptor.getName().equals( fieldOwnerClassName ) ) {
|
||||
logger.trace( "accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
|
||||
return true;
|
||||
}
|
||||
else if ( options.performExtendedInstrumentation() && classNames.contains( fieldOwnerClassName ) ) {
|
||||
logger.trace( "accepting extended transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.trace( "rejecting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]; caller = " + transformingClassName );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General strategy contract for handling entries in an archive file.
|
||||
*/
|
||||
private static interface ZipEntryHandler {
|
||||
/**
|
||||
* Apply strategy to the given archive entry.
|
||||
*
|
||||
* @param entry The archive file entry.
|
||||
* @param byteCode The bytes making up the entry
|
||||
*
|
||||
* @throws Exception Problem handling entry
|
||||
*/
|
||||
public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies {@link ZipEntryHandler} strategies to the entries of an archive file.
|
||||
*/
|
||||
private static class ZipFileProcessor {
|
||||
private final ZipEntryHandler entryHandler;
|
||||
|
||||
public ZipFileProcessor(ZipEntryHandler entryHandler) {
|
||||
this.entryHandler = entryHandler;
|
||||
}
|
||||
|
||||
public void process(File file) throws Exception {
|
||||
final ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
|
||||
|
||||
try {
|
||||
ZipEntry entry;
|
||||
while ( (entry = zip.getNextEntry()) != null ) {
|
||||
final byte[] bytes = ByteCodeHelper.readByteCode( zip );
|
||||
entryHandler.handleEntry( entry, bytes );
|
||||
zip.closeEntry();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
zip.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* BasicClassFilter provides class filtering based on a series of packages to
|
||||
* be included and/or a series of explicit class names to be included. If
|
||||
* neither is specified, then no restrictions are applied.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicClassFilter implements ClassFilter {
|
||||
private final String[] includedPackages;
|
||||
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 ) {
|
||||
this.includedClassNames.addAll( Arrays.asList( includedClassNames ) );
|
||||
}
|
||||
|
||||
isAllEmpty = ( this.includedPackages == null || this.includedPackages.length == 0 )
|
||||
&& ( this.includedClassNames.isEmpty() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldInstrumentClass(String className) {
|
||||
return isAllEmpty ||
|
||||
includedClassNames.contains( className ) ||
|
||||
isInIncludedPackage( className );
|
||||
}
|
||||
|
||||
private boolean isInIncludedPackage(String className) {
|
||||
if ( includedPackages != null ) {
|
||||
for ( String includedPackage : includedPackages ) {
|
||||
if ( className.startsWith( includedPackage ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
/**
|
||||
* Contract describing the information Hibernate needs in terms of instrumenting
|
||||
* a class, either via ant task or dynamic classloader.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ClassDescriptor {
|
||||
/**
|
||||
* The name of the class.
|
||||
*
|
||||
* @return The class name.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Determine if the class is already instrumented.
|
||||
*
|
||||
* @return True if already instrumented; false otherwise.
|
||||
*/
|
||||
public boolean isInstrumented();
|
||||
|
||||
/**
|
||||
* The bytes making up the class' bytecode.
|
||||
*
|
||||
* @return The bytecode bytes.
|
||||
*/
|
||||
public byte[] getBytes();
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
/**
|
||||
* Used to determine whether a class should be instrumented.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ClassFilter {
|
||||
/**
|
||||
* Should this class be included in instrumentation.
|
||||
*
|
||||
* @param className The name of the class to check
|
||||
*
|
||||
* @return {@literal true} to include class in instrumentation; {@literal false} otherwise.
|
||||
*/
|
||||
public boolean shouldInstrumentClass(String className);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
/**
|
||||
* Indicates problem performing the instrumentation execution.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@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 );
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
/**
|
||||
* Used to determine whether a field reference should be instrumented.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface FieldFilter {
|
||||
/**
|
||||
* Should this field definition be instrumented?
|
||||
*
|
||||
* @param className The name of the class currently being processed
|
||||
* @param fieldName The name of the field being checked.
|
||||
* @return True if we should instrument this field.
|
||||
*/
|
||||
public boolean shouldInstrumentField(String className, String fieldName);
|
||||
|
||||
/**
|
||||
* Should we instrument *access to* the given field. This differs from
|
||||
* {@link #shouldInstrumentField} in that here we are talking about a particular usage of
|
||||
* a field.
|
||||
*
|
||||
* @param transformingClassName The class currently being transformed.
|
||||
* @param fieldOwnerClassName The name of the class owning this field being checked.
|
||||
* @param fieldName The name of the field being checked.
|
||||
* @return True if this access should be transformed.
|
||||
*/
|
||||
public boolean shouldTransformFieldAccess(String transformingClassName, String fieldOwnerClassName, String fieldName);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Basic contract for performing instrumentation.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Instrumenter {
|
||||
/**
|
||||
* Perform the instrumentation.
|
||||
*
|
||||
* @param files The file on which to perform instrumentation
|
||||
*/
|
||||
public void execute(Set<File> files);
|
||||
|
||||
/**
|
||||
* Instrumentation options.
|
||||
*/
|
||||
public static interface Options {
|
||||
/**
|
||||
* Should we enhance references to class fields outside the class itself?
|
||||
*
|
||||
* @return {@literal true}/{@literal false}
|
||||
*/
|
||||
public boolean performExtendedInstrumentation();
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.buildtime.spi;
|
||||
|
||||
/**
|
||||
* Provides an abstraction for how instrumentation does logging because it is usually run in environments (Ant/Maven)
|
||||
* with their own logging infrastructure. This abstraction allows proper bridging.
|
||||
*
|
||||
* @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);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
|
@ -25,7 +25,7 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
|||
import org.hibernate.bytecode.enhance.spi.EnhancementException;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
|
||||
|
@ -315,7 +315,7 @@ public class EntityEnhancer extends Enhancer {
|
|||
EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME,
|
||||
EnhancerConstants.TRACKER_COLLECTION_NAME,
|
||||
COLLECTION_TRACKER_IMPL,
|
||||
LazyAttributeLoader.class.getName()
|
||||
LazyAttributeLoadingInterceptor.class.getName()
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -324,7 +324,7 @@ public class EntityEnhancer extends Enhancer {
|
|||
String.format(
|
||||
" if(%1$s != null && %1$s instanceof %2$s) lazyInterceptor = (%2$s) %1$s;%n%n",
|
||||
EnhancerConstants.INTERCEPTOR_FIELD_NAME,
|
||||
LazyAttributeLoader.class.getName()
|
||||
LazyAttributeLoadingInterceptor.class.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.spi;
|
||||
package org.hibernate.bytecode.enhance.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
|
@ -16,7 +16,7 @@ import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
|
|||
import org.hibernate.bytecode.enhance.spi.CollectionTracker;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.Helper.Consumer;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.Helper.LazyInitializationWork;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -30,8 +30,8 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
public class LazyAttributeLoader implements PersistentAttributeInterceptor, Consumer {
|
||||
private static final Logger log = Logger.getLogger( LazyAttributeLoader.class );
|
||||
public class LazyAttributeLoadingInterceptor implements PersistentAttributeInterceptor, Consumer {
|
||||
private static final Logger log = Logger.getLogger( LazyAttributeLoadingInterceptor.class );
|
||||
|
||||
private transient SessionImplementor session;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class LazyAttributeLoader implements PersistentAttributeInterceptor, Cons
|
|||
|
||||
private final SimpleFieldTracker initializedFields = new SimpleFieldTracker();
|
||||
|
||||
public LazyAttributeLoader(SessionImplementor session, Set<String> lazyFields, String entityName) {
|
||||
public LazyAttributeLoadingInterceptor(SessionImplementor session, Set<String> lazyFields, String entityName) {
|
||||
this.session = session;
|
||||
this.lazyFields = lazyFields;
|
||||
this.entityName = entityName;
|
||||
|
@ -130,7 +130,7 @@ public class LazyAttributeLoader implements PersistentAttributeInterceptor, Cons
|
|||
return lazyFields == null || !lazyFields.contains( fieldName ) || initializedFields.contains( fieldName );
|
||||
}
|
||||
|
||||
public boolean isUninitialized() {
|
||||
public boolean hasAnyUninitializedAttributes() {
|
||||
if ( lazyFields != null ) {
|
||||
for ( String fieldName : lazyFields ) {
|
||||
if ( !initializedFields.contains( fieldName ) ) {
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.internal.javassist.JavassistHelper;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Helper class for dealing with enhanced entity classes.
|
||||
*
|
||||
* These operations are expensive. They are only meant to be used when code does not have access to a
|
||||
* SessionFactory (namely from the instrumentation tasks). When code has access to a SessionFactory,
|
||||
* {@link org.hibernate.bytecode.spi.EntityInstrumentationMetadata} should be used instead to query the
|
||||
* instrumentation state. EntityInstrumentationMetadata is accessed from the
|
||||
* {@link org.hibernate.persister.entity.EntityPersister} via the
|
||||
* {@link org.hibernate.persister.entity.EntityPersister#getInstrumentationMetadata()} method.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class FieldInterceptionHelper {
|
||||
private static final Set<Delegate> INSTRUMENTATION_DELEGATES = buildInstrumentationDelegates();
|
||||
|
||||
private static Set<Delegate> buildInstrumentationDelegates() {
|
||||
final HashSet<Delegate> delegates = new HashSet<Delegate>();
|
||||
delegates.add( JavassistDelegate.INSTANCE );
|
||||
return delegates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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( object );
|
||||
if ( interceptor != null ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
if ( entity == null ) {
|
||||
return null;
|
||||
}
|
||||
FieldInterceptor interceptor = null;
|
||||
for ( Delegate delegate : INSTRUMENTATION_DELEGATES ) {
|
||||
interceptor = delegate.injectInterceptor( entity, entityName, uninitializedFieldNames, session );
|
||||
if ( interceptor != null ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
private static interface Delegate {
|
||||
public boolean isInstrumented(Class classToCheck);
|
||||
public FieldInterceptor extractInterceptor(Object entity);
|
||||
public FieldInterceptor injectInterceptor(Object entity, String entityName, Set uninitializedFieldNames, SessionImplementor session);
|
||||
}
|
||||
|
||||
private static class JavassistDelegate implements Delegate {
|
||||
public static final JavassistDelegate INSTANCE = new JavassistDelegate();
|
||||
public static final String MARKER = "org.hibernate.bytecode.internal.javassist.FieldHandled";
|
||||
|
||||
@Override
|
||||
public boolean isInstrumented(Class classToCheck) {
|
||||
for ( Class definedInterface : classToCheck.getInterfaces() ) {
|
||||
if ( MARKER.equals( definedInterface.getName() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor extractInterceptor(Object entity) {
|
||||
for ( Class definedInterface : entity.getClass().getInterfaces() ) {
|
||||
if ( MARKER.equals( definedInterface.getName() ) ) {
|
||||
return JavassistHelper.extractFieldInterceptor( entity );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
String entityName,
|
||||
Set uninitializedFieldNames,
|
||||
SessionImplementor session) {
|
||||
for ( Class definedInterface : entity.getClass().getInterfaces() ) {
|
||||
if ( MARKER.equals( definedInterface.getName() ) ) {
|
||||
return JavassistHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInterceptionHelper() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal.javassist;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.spi.AbstractFieldInterceptor;
|
||||
import org.hibernate.bytecode.internal.javassist.FieldHandler;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
|
||||
/**
|
||||
* A field-level interceptor that initializes lazily fetched properties.
|
||||
* This interceptor can be attached to classes instrumented by Javassist.
|
||||
* Note that this implementation assumes that the instance variable
|
||||
* name is the same as the name of the persistent property that must
|
||||
* be loaded.
|
||||
* </p>
|
||||
* Note: most of the interesting functionality here is farmed off
|
||||
* to the super-class. The stuff here mainly acts as an adapter to the
|
||||
* Javassist-specific functionality, routing interception through
|
||||
* the super-class's intercept() method
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
final class FieldInterceptorImpl extends AbstractFieldInterceptor implements FieldHandler, Serializable {
|
||||
|
||||
FieldInterceptorImpl(SessionImplementor session, Set uninitializedFields, String entityName) {
|
||||
super( session, uninitializedFields, entityName );
|
||||
}
|
||||
|
||||
|
||||
// FieldHandler impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@Override
|
||||
public boolean readBoolean(Object target, String name, boolean oldValue) {
|
||||
return (Boolean) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public byte readByte(Object target, String name, byte oldValue) {
|
||||
return (Byte) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public char readChar(Object target, String name, char oldValue) {
|
||||
return (Character) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public double readDouble(Object target, String name, double oldValue) {
|
||||
return (Double) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public float readFloat(Object target, String name, float oldValue) {
|
||||
return (Float) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public int readInt(Object target, String name, int oldValue) {
|
||||
return (Integer) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public long readLong(Object target, String name, long oldValue) {
|
||||
return (Long) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public short readShort(Object target, String name, short oldValue) {
|
||||
return (Short) intercept( target, name, oldValue );
|
||||
}
|
||||
@Override
|
||||
public Object readObject(Object target, String name, Object oldValue) {
|
||||
Object value = intercept( target, name, oldValue );
|
||||
if ( value instanceof HibernateProxy ) {
|
||||
final LazyInitializer li = ( (HibernateProxy) value ).getHibernateLazyInitializer();
|
||||
if ( li.isUnwrap() ) {
|
||||
value = li.getImplementation();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@Override
|
||||
public boolean writeBoolean(Object target, String name, boolean oldValue, boolean newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public byte writeByte(Object target, String name, byte oldValue, byte newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public char writeChar(Object target, String name, char oldValue, char newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public double writeDouble(Object target, String name, double oldValue, double newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public float writeFloat(Object target, String name, float oldValue, float newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public int writeInt(Object target, String name, int oldValue, int newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public long writeLong(Object target, String name, long oldValue, long newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public short writeShort(Object target, String name, short oldValue, short newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public Object writeObject(Object target, String name, Object oldValue, Object newValue) {
|
||||
dirty();
|
||||
intercept( target, name, oldValue );
|
||||
return newValue;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FieldInterceptorImpl(entityName=" + getEntityName() +
|
||||
",dirty=" + isDirty() +
|
||||
",uninitializedFields=" + getUninitializedFields() +
|
||||
')';
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal.javassist;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
final FieldInterceptorImpl fieldInterceptor = new FieldInterceptorImpl( session, uninitializedFieldNames, entityName );
|
||||
( (FieldHandled) entity ).setFieldHandler( fieldInterceptor );
|
||||
return fieldInterceptor;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Javassist support internals
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal.javassist;
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bytecode instrumentation internals
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.internal;
|
|
@ -1,15 +0,0 @@
|
|||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>
|
||||
This package implements an interception mechanism for lazy property fetching, based on bytecode instrumentation.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.spi;
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
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 {
|
||||
|
||||
private transient SessionImplementor session;
|
||||
private Set uninitializedFields;
|
||||
private final String entityName;
|
||||
|
||||
private transient boolean initializing;
|
||||
private boolean dirty;
|
||||
|
||||
protected AbstractFieldInterceptor(SessionImplementor session, Set uninitializedFields, String entityName) {
|
||||
this.session = session;
|
||||
this.uninitializedFields = uninitializedFields;
|
||||
this.entityName = entityName;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if ( uninitializedFields != null && uninitializedFields.contains( fieldName ) ) {
|
||||
if ( session == null ) {
|
||||
throw new LazyInitializationException( "entity with lazy properties is not associated with a session" );
|
||||
}
|
||||
else if ( !session.isOpen() || !session.isConnected() ) {
|
||||
throw new LazyInitializationException( "session is not connected" );
|
||||
}
|
||||
|
||||
final Object result;
|
||||
initializing = true;
|
||||
try {
|
||||
result = ( (LazyPropertyInitializer) session.getFactory().getEntityPersister( entityName ) )
|
||||
.initializeLazyProperty( fieldName, target, session );
|
||||
}
|
||||
finally {
|
||||
initializing = false;
|
||||
}
|
||||
// let's assume that there is only one lazy fetch group, for now!
|
||||
uninitializedFields = null;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.instrumentation.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Contract for field interception handlers.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface FieldInterceptor {
|
||||
|
||||
/**
|
||||
* Use to associate the entity to which we are bound to the given session.
|
||||
*
|
||||
* @param session The session to which we are now associated.
|
||||
*/
|
||||
public void setSession(SessionImplementor session);
|
||||
|
||||
/**
|
||||
* Is the entity to which we are bound completely initialized?
|
||||
*
|
||||
* @return True if the entity is initialized; otherwise false.
|
||||
*/
|
||||
public boolean isInitialized();
|
||||
|
||||
/**
|
||||
* The the given field initialized for the entity to which we are bound?
|
||||
*
|
||||
* @param field The name of the field to check
|
||||
* @return True if the given field is initialized; otherwise false.
|
||||
*/
|
||||
public boolean isInitialized(String field);
|
||||
|
||||
/**
|
||||
* Forcefully mark the entity as being dirty.
|
||||
*/
|
||||
public void dirty();
|
||||
|
||||
/**
|
||||
* Is the entity considered dirty?
|
||||
*
|
||||
* @return True if the entity is dirty; otherwise false.
|
||||
*/
|
||||
public boolean isDirty();
|
||||
|
||||
/**
|
||||
* Clear the internal dirty flag.
|
||||
*/
|
||||
public void clearDirty();
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
|
@ -7,19 +7,10 @@
|
|||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.spi.ClassFilter;
|
||||
import org.hibernate.bytecode.buildtime.spi.FieldFilter;
|
||||
import org.hibernate.bytecode.instrumentation.internal.javassist.JavassistHelper;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeProvider;
|
||||
import org.hibernate.bytecode.spi.ClassTransformer;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.bytecode.spi.NotInstrumentedException;
|
||||
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
|
@ -101,71 +92,4 @@ public class BytecodeProviderImpl implements BytecodeProvider {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter) {
|
||||
return new JavassistClassTransformer( classFilter, fieldFilter );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityInstrumentationMetadata getEntityInstrumentationMetadata(Class entityClass) {
|
||||
return new EntityInstrumentationMetadataImpl( entityClass );
|
||||
}
|
||||
|
||||
private static class EntityInstrumentationMetadataImpl implements EntityInstrumentationMetadata {
|
||||
private final Class entityClass;
|
||||
private final boolean isInstrumented;
|
||||
|
||||
private EntityInstrumentationMetadataImpl(Class entityClass) {
|
||||
this.entityClass = entityClass;
|
||||
this.isInstrumented = FieldHandled.class.isAssignableFrom( entityClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return entityClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstrumented() {
|
||||
return isInstrumented;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor extractInterceptor(Object entity) throws NotInstrumentedException {
|
||||
if ( !entityClass.isInstance( entity ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Passed entity instance [%s] is not of expected type [%s]",
|
||||
entity,
|
||||
getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( ! isInstrumented() ) {
|
||||
throw new NotInstrumentedException( String.format( "Entity class [%s] is not instrumented", getEntityName() ) );
|
||||
}
|
||||
return JavassistHelper.extractFieldInterceptor( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
String entityName,
|
||||
Set uninitializedFieldNames,
|
||||
SessionImplementor session) throws NotInstrumentedException {
|
||||
if ( !entityClass.isInstance( entity ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Passed entity instance [%s] is not of expected type [%s]",
|
||||
entity,
|
||||
getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( ! isInstrumented() ) {
|
||||
throw new NotInstrumentedException( String.format( "Entity class [%s] is not instrumented", getEntityName() ) );
|
||||
}
|
||||
return JavassistHelper.injectFieldInterceptor( entity, entityName, uninitializedFieldNames, session );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
/**
|
||||
* Contract for deciding whether fields should be read and/or write intercepted.
|
||||
*
|
||||
* @author Muga Nishizawa
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface FieldFilter {
|
||||
/**
|
||||
* Should the given field be read intercepted?
|
||||
*
|
||||
* @param desc The field descriptor
|
||||
* @param name The field name
|
||||
*
|
||||
* @return true if the given field should be read intercepted; otherwise
|
||||
* false.
|
||||
*/
|
||||
boolean handleRead(String desc, String name);
|
||||
|
||||
/**
|
||||
* Should the given field be write intercepted?
|
||||
*
|
||||
* @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);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
/**
|
||||
* Interface introduced to the enhanced class in order to be able to
|
||||
* inject a {@link FieldHandler} to define the interception behavior.
|
||||
*
|
||||
* @author Muga Nishizawa
|
||||
*/
|
||||
public interface FieldHandled {
|
||||
/**
|
||||
* Inject the field interception handler to be used.
|
||||
*
|
||||
* @param handler The field interception handler.
|
||||
*/
|
||||
public void setFieldHandler(FieldHandler handler);
|
||||
|
||||
/**
|
||||
* Access to the current field interception handler.
|
||||
*
|
||||
* @return The current field interception handler.
|
||||
*/
|
||||
public FieldHandler getFieldHandler();
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
/**
|
||||
* The interface defining how interception of a field should be handled.
|
||||
*
|
||||
* @author Muga Nishizawa
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public interface FieldHandler {
|
||||
|
||||
/**
|
||||
* Called to handle writing 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
|
||||
* @param newValue The new field value.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
|
@ -1,734 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.bytecode.AccessFlag;
|
||||
import javassist.bytecode.BadBytecode;
|
||||
import javassist.bytecode.Bytecode;
|
||||
import javassist.bytecode.ClassFile;
|
||||
import javassist.bytecode.CodeAttribute;
|
||||
import javassist.bytecode.CodeIterator;
|
||||
import javassist.bytecode.ConstPool;
|
||||
import javassist.bytecode.Descriptor;
|
||||
import javassist.bytecode.FieldInfo;
|
||||
import javassist.bytecode.MethodInfo;
|
||||
import javassist.bytecode.Opcode;
|
||||
import javassist.bytecode.StackMapTable;
|
||||
import javassist.bytecode.stackmap.MapMaker;
|
||||
|
||||
/**
|
||||
* The thing that handles actual class enhancement in regards to
|
||||
* intercepting field accesses.
|
||||
*
|
||||
* @author Muga Nishizawa
|
||||
* @author Steve Ebersole
|
||||
* @author Dustin Schultz
|
||||
*/
|
||||
public class FieldTransformer {
|
||||
|
||||
private static final String EACH_READ_METHOD_PREFIX = "$javassist_read_";
|
||||
|
||||
private static final String EACH_WRITE_METHOD_PREFIX = "$javassist_write_";
|
||||
|
||||
private static final String FIELD_HANDLED_TYPE_NAME = FieldHandled.class.getName();
|
||||
|
||||
private static final String HANDLER_FIELD_NAME = "$JAVASSIST_READ_WRITE_HANDLER";
|
||||
|
||||
private static final String FIELD_HANDLER_TYPE_NAME = FieldHandler.class.getName();
|
||||
|
||||
private static final String HANDLER_FIELD_DESCRIPTOR = 'L' + FIELD_HANDLER_TYPE_NAME.replace( '.', '/' ) + ';';
|
||||
|
||||
private static final String GETFIELDHANDLER_METHOD_NAME = "getFieldHandler";
|
||||
|
||||
private static final String SETFIELDHANDLER_METHOD_NAME = "setFieldHandler";
|
||||
|
||||
private static final String GETFIELDHANDLER_METHOD_DESCRIPTOR = "()" + HANDLER_FIELD_DESCRIPTOR;
|
||||
|
||||
private static final String SETFIELDHANDLER_METHOD_DESCRIPTOR = "(" + HANDLER_FIELD_DESCRIPTOR + ")V";
|
||||
|
||||
private final FieldFilter filter;
|
||||
private final ClassPool classPool;
|
||||
|
||||
FieldTransformer(FieldFilter f, ClassPool c) {
|
||||
filter = f;
|
||||
classPool = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the class contained in the given file, writing the result back to the same file.
|
||||
*
|
||||
* @param file The file containing the class to be transformed
|
||||
*
|
||||
* @throws Exception Indicates a problem performing the transformation
|
||||
*/
|
||||
public void transform(File file) throws Exception {
|
||||
final DataInputStream in = new DataInputStream( new FileInputStream( file ) );
|
||||
final ClassFile classfile = new ClassFile( in );
|
||||
transform( classfile );
|
||||
|
||||
final DataOutputStream out = new DataOutputStream( new FileOutputStream( file ) );
|
||||
try {
|
||||
classfile.write( out );
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the class defined by the given ClassFile descriptor. The ClassFile descriptor itself is mutated
|
||||
*
|
||||
* @param classFile The class file descriptor
|
||||
*
|
||||
* @throws Exception Indicates a problem performing the transformation
|
||||
*/
|
||||
public void transform(ClassFile classFile) throws Exception {
|
||||
if ( classFile.isInterface() ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
addFieldHandlerField( classFile );
|
||||
addGetFieldHandlerMethod( classFile );
|
||||
addSetFieldHandlerMethod( classFile );
|
||||
addFieldHandledInterface( classFile );
|
||||
addReadWriteMethods( classFile );
|
||||
transformInvokevirtualsIntoPutAndGetfields( classFile );
|
||||
}
|
||||
catch (CannotCompileException e) {
|
||||
throw new RuntimeException( e.getMessage(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private void addFieldHandlerField(ClassFile classfile) throws CannotCompileException {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final FieldInfo fieldInfo = new FieldInfo( constPool, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR );
|
||||
fieldInfo.setAccessFlags( AccessFlag.PRIVATE | AccessFlag.TRANSIENT );
|
||||
classfile.addField( fieldInfo );
|
||||
}
|
||||
|
||||
private void addGetFieldHandlerMethod(ClassFile classfile) throws CannotCompileException, BadBytecode {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int thisClassInfo = constPool.getThisClassInfo();
|
||||
final MethodInfo getterMethodInfo = new MethodInfo(
|
||||
constPool,
|
||||
GETFIELDHANDLER_METHOD_NAME,
|
||||
GETFIELDHANDLER_METHOD_DESCRIPTOR
|
||||
);
|
||||
|
||||
/* local variable | this | */
|
||||
final Bytecode code = new Bytecode( constPool, 2, 1 );
|
||||
// aload_0 // load this
|
||||
code.addAload( 0 );
|
||||
// getfield // get field "$JAVASSIST_CALLBACK" defined already
|
||||
code.addOpcode( Opcode.GETFIELD );
|
||||
final int fieldIndex = constPool.addFieldrefInfo( thisClassInfo, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR );
|
||||
code.addIndex( fieldIndex );
|
||||
// areturn // return the value of the field
|
||||
code.addOpcode( Opcode.ARETURN );
|
||||
getterMethodInfo.setCodeAttribute( code.toCodeAttribute() );
|
||||
getterMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
|
||||
final CodeAttribute codeAttribute = getterMethodInfo.getCodeAttribute();
|
||||
if ( codeAttribute != null ) {
|
||||
final StackMapTable smt = MapMaker.make( classPool, getterMethodInfo );
|
||||
codeAttribute.setAttribute( smt );
|
||||
}
|
||||
classfile.addMethod( getterMethodInfo );
|
||||
}
|
||||
|
||||
private void addSetFieldHandlerMethod(ClassFile classfile) throws CannotCompileException, BadBytecode {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int thisClassInfo = constPool.getThisClassInfo();
|
||||
final MethodInfo methodInfo = new MethodInfo(
|
||||
constPool,
|
||||
SETFIELDHANDLER_METHOD_NAME,
|
||||
SETFIELDHANDLER_METHOD_DESCRIPTOR
|
||||
);
|
||||
|
||||
/* local variables | this | callback | */
|
||||
final Bytecode code = new Bytecode(constPool, 3, 3);
|
||||
// aload_0 : load this
|
||||
code.addAload( 0 );
|
||||
// aload_1 : load callback
|
||||
code.addAload( 1 );
|
||||
// putfield // put field "$JAVASSIST_CALLBACK" defined already
|
||||
code.addOpcode( Opcode.PUTFIELD );
|
||||
final int fieldIndex = constPool.addFieldrefInfo( thisClassInfo, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR );
|
||||
code.addIndex( fieldIndex );
|
||||
// return
|
||||
code.addOpcode( Opcode.RETURN );
|
||||
methodInfo.setCodeAttribute( code.toCodeAttribute() );
|
||||
methodInfo.setAccessFlags( AccessFlag.PUBLIC );
|
||||
final CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
|
||||
if ( codeAttribute != null ) {
|
||||
final StackMapTable smt = MapMaker.make( classPool, methodInfo );
|
||||
codeAttribute.setAttribute( smt );
|
||||
}
|
||||
classfile.addMethod( methodInfo );
|
||||
}
|
||||
|
||||
private void addFieldHandledInterface(ClassFile classfile) {
|
||||
final String[] interfaceNames = classfile.getInterfaces();
|
||||
final String[] newInterfaceNames = new String[interfaceNames.length + 1];
|
||||
System.arraycopy( interfaceNames, 0, newInterfaceNames, 0, interfaceNames.length );
|
||||
newInterfaceNames[newInterfaceNames.length - 1] = FIELD_HANDLED_TYPE_NAME;
|
||||
classfile.setInterfaces( newInterfaceNames );
|
||||
}
|
||||
|
||||
private void addReadWriteMethods(ClassFile classfile) throws CannotCompileException, BadBytecode {
|
||||
final List fields = classfile.getFields();
|
||||
for ( Object field : fields ) {
|
||||
final FieldInfo finfo = (FieldInfo) field;
|
||||
if ( (finfo.getAccessFlags() & AccessFlag.STATIC) == 0 && (!finfo.getName().equals( HANDLER_FIELD_NAME )) ) {
|
||||
// case of non-static field
|
||||
if ( filter.handleRead( finfo.getDescriptor(), finfo.getName() ) ) {
|
||||
addReadMethod( classfile, finfo );
|
||||
}
|
||||
if ( filter.handleWrite( finfo.getDescriptor(), finfo.getName() ) ) {
|
||||
addWriteMethod( classfile, finfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addReadMethod(ClassFile classfile, FieldInfo finfo) throws CannotCompileException, BadBytecode {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int thisClassInfo = constPool.getThisClassInfo();
|
||||
final String readMethodDescriptor = "()" + finfo.getDescriptor();
|
||||
final MethodInfo readMethodInfo = new MethodInfo(
|
||||
constPool,
|
||||
EACH_READ_METHOD_PREFIX + finfo.getName(),
|
||||
readMethodDescriptor
|
||||
);
|
||||
|
||||
/* local variables | target obj | each oldvalue | */
|
||||
final Bytecode code = new Bytecode(constPool, 5, 3);
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// getfield // get each field
|
||||
code.addOpcode( Opcode.GETFIELD );
|
||||
final int baseFieldIndex = constPool.addFieldrefInfo( thisClassInfo, finfo.getName(), finfo.getDescriptor() );
|
||||
code.addIndex( baseFieldIndex );
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// invokeinterface : invoke Enabled.getInterceptFieldCallback()
|
||||
final int enabledClassIndex = constPool.addClassInfo( FIELD_HANDLED_TYPE_NAME );
|
||||
code.addInvokeinterface(
|
||||
enabledClassIndex,
|
||||
GETFIELDHANDLER_METHOD_NAME,
|
||||
GETFIELDHANDLER_METHOD_DESCRIPTOR,
|
||||
1
|
||||
);
|
||||
// ifnonnull
|
||||
code.addOpcode( Opcode.IFNONNULL );
|
||||
code.addIndex( 4 );
|
||||
// *return // each type
|
||||
addTypeDependDataReturn( code, finfo.getDescriptor() );
|
||||
// *store_1 // each type
|
||||
addTypeDependDataStore( code, finfo.getDescriptor(), 1 );
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// invokeinterface // invoke Enabled.getInterceptFieldCallback()
|
||||
code.addInvokeinterface(
|
||||
enabledClassIndex,
|
||||
GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
|
||||
1
|
||||
);
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// ldc // name of the field
|
||||
code.addLdc( finfo.getName() );
|
||||
// *load_1 // each type
|
||||
addTypeDependDataLoad( code, finfo.getDescriptor(), 1 );
|
||||
// invokeinterface // invoke Callback.read*() // each type
|
||||
addInvokeFieldHandlerMethod(
|
||||
classfile, code, finfo.getDescriptor(),
|
||||
true
|
||||
);
|
||||
// *return // each type
|
||||
addTypeDependDataReturn( code, finfo.getDescriptor() );
|
||||
|
||||
readMethodInfo.setCodeAttribute( code.toCodeAttribute() );
|
||||
readMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
|
||||
final CodeAttribute codeAttribute = readMethodInfo.getCodeAttribute();
|
||||
if ( codeAttribute != null ) {
|
||||
final StackMapTable smt = MapMaker.make( classPool, readMethodInfo );
|
||||
codeAttribute.setAttribute( smt );
|
||||
}
|
||||
classfile.addMethod( readMethodInfo );
|
||||
}
|
||||
|
||||
private void addWriteMethod(ClassFile classfile, FieldInfo finfo) throws CannotCompileException, BadBytecode {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int thisClassInfo = constPool.getThisClassInfo();
|
||||
final String writeMethodDescriptor = "(" + finfo.getDescriptor() + ")V";
|
||||
final MethodInfo writeMethodInfo = new MethodInfo(
|
||||
constPool,
|
||||
EACH_WRITE_METHOD_PREFIX+ finfo.getName(),
|
||||
writeMethodDescriptor
|
||||
);
|
||||
|
||||
/* local variables | target obj | each oldvalue | */
|
||||
final Bytecode code = new Bytecode(constPool, 6, 3);
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// invokeinterface : enabled.getInterceptFieldCallback()
|
||||
final int enabledClassIndex = constPool.addClassInfo( FIELD_HANDLED_TYPE_NAME );
|
||||
code.addInvokeinterface(
|
||||
enabledClassIndex,
|
||||
GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR,
|
||||
1
|
||||
);
|
||||
// ifnonnull (label1)
|
||||
code.addOpcode( Opcode.IFNONNULL );
|
||||
code.addIndex( 9 );
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// *load_1
|
||||
addTypeDependDataLoad( code, finfo.getDescriptor(), 1 );
|
||||
// putfield
|
||||
code.addOpcode( Opcode.PUTFIELD );
|
||||
final int baseFieldIndex = constPool.addFieldrefInfo( thisClassInfo, finfo.getName(), finfo.getDescriptor() );
|
||||
code.addIndex( baseFieldIndex );
|
||||
code.growStack( -Descriptor.dataSize( finfo.getDescriptor() ) );
|
||||
// return ;
|
||||
code.addOpcode( Opcode.RETURN );
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// dup
|
||||
code.addOpcode( Opcode.DUP );
|
||||
// invokeinterface // enabled.getInterceptFieldCallback()
|
||||
code.addInvokeinterface(
|
||||
enabledClassIndex,
|
||||
GETFIELDHANDLER_METHOD_NAME,
|
||||
GETFIELDHANDLER_METHOD_DESCRIPTOR,
|
||||
1
|
||||
);
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// ldc // field name
|
||||
code.addLdc( finfo.getName() );
|
||||
// aload_0
|
||||
code.addAload( 0 );
|
||||
// getfield // old value of the field
|
||||
code.addOpcode( Opcode.GETFIELD );
|
||||
code.addIndex( baseFieldIndex );
|
||||
code.growStack( Descriptor.dataSize( finfo.getDescriptor() ) - 1 );
|
||||
// *load_1
|
||||
addTypeDependDataLoad( code, finfo.getDescriptor(), 1 );
|
||||
// invokeinterface // callback.write*(..)
|
||||
addInvokeFieldHandlerMethod( classfile, code, finfo.getDescriptor(), false );
|
||||
// putfield // new value of the field
|
||||
code.addOpcode( Opcode.PUTFIELD );
|
||||
code.addIndex( baseFieldIndex );
|
||||
code.growStack( -Descriptor.dataSize( finfo.getDescriptor() ) );
|
||||
// return
|
||||
code.addOpcode( Opcode.RETURN );
|
||||
|
||||
writeMethodInfo.setCodeAttribute( code.toCodeAttribute() );
|
||||
writeMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
|
||||
final CodeAttribute codeAttribute = writeMethodInfo.getCodeAttribute();
|
||||
if ( codeAttribute != null ) {
|
||||
final StackMapTable smt = MapMaker.make( classPool, writeMethodInfo );
|
||||
codeAttribute.setAttribute( smt );
|
||||
}
|
||||
classfile.addMethod( writeMethodInfo );
|
||||
}
|
||||
|
||||
private void transformInvokevirtualsIntoPutAndGetfields(ClassFile classfile) throws CannotCompileException, BadBytecode {
|
||||
for ( Object o : classfile.getMethods() ) {
|
||||
final MethodInfo methodInfo = (MethodInfo) o;
|
||||
final String methodName = methodInfo.getName();
|
||||
if ( methodName.startsWith( EACH_READ_METHOD_PREFIX )
|
||||
|| methodName.startsWith( EACH_WRITE_METHOD_PREFIX )
|
||||
|| methodName.equals( GETFIELDHANDLER_METHOD_NAME )
|
||||
|| methodName.equals( SETFIELDHANDLER_METHOD_NAME ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final CodeAttribute codeAttr = methodInfo.getCodeAttribute();
|
||||
if ( codeAttr == null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final CodeIterator iter = codeAttr.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
int pos = iter.next();
|
||||
pos = transformInvokevirtualsIntoGetfields( classfile, iter, pos );
|
||||
transformInvokevirtualsIntoPutfields( classfile, iter, pos );
|
||||
}
|
||||
final StackMapTable smt = MapMaker.make( classPool, methodInfo );
|
||||
codeAttr.setAttribute( smt );
|
||||
}
|
||||
}
|
||||
|
||||
private int transformInvokevirtualsIntoGetfields(ClassFile classfile, CodeIterator iter, int pos) {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int c = iter.byteAt( pos );
|
||||
if ( c != Opcode.GETFIELD ) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
final int index = iter.u16bitAt( pos + 1 );
|
||||
final String fieldName = constPool.getFieldrefName( index );
|
||||
final String className = constPool.getFieldrefClassName( index );
|
||||
if ( !filter.handleReadAccess( className, fieldName ) ) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
final String fieldReaderMethodDescriptor = "()" + constPool.getFieldrefType( index );
|
||||
final int fieldReaderMethodIndex = constPool.addMethodrefInfo(
|
||||
constPool.getThisClassInfo(),
|
||||
EACH_READ_METHOD_PREFIX + fieldName,
|
||||
fieldReaderMethodDescriptor
|
||||
);
|
||||
iter.writeByte( Opcode.INVOKEVIRTUAL, pos );
|
||||
iter.write16bit( fieldReaderMethodIndex, pos + 1 );
|
||||
return pos;
|
||||
}
|
||||
|
||||
private int transformInvokevirtualsIntoPutfields(ClassFile classfile, CodeIterator iter, int pos) {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
final int c = iter.byteAt( pos );
|
||||
if ( c != Opcode.PUTFIELD ) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
final int index = iter.u16bitAt( pos + 1 );
|
||||
final String fieldName = constPool.getFieldrefName( index );
|
||||
final String className = constPool.getFieldrefClassName( index );
|
||||
if ( !filter.handleWriteAccess( className, fieldName ) ) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
final String fieldWriterMethodDescriptor = "(" + constPool.getFieldrefType( index ) + ")V";
|
||||
final int fieldWriterMethodIndex = constPool.addMethodrefInfo(
|
||||
constPool.getThisClassInfo(),
|
||||
EACH_WRITE_METHOD_PREFIX + fieldName,
|
||||
fieldWriterMethodDescriptor
|
||||
);
|
||||
iter.writeByte( Opcode.INVOKEVIRTUAL, pos );
|
||||
iter.write16bit( fieldWriterMethodIndex, pos + 1 );
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static void addInvokeFieldHandlerMethod(
|
||||
ClassFile classfile,
|
||||
Bytecode code,
|
||||
String typeName,
|
||||
boolean isReadMethod) {
|
||||
final ConstPool constPool = classfile.getConstPool();
|
||||
// invokeinterface
|
||||
final int callbackTypeIndex = constPool.addClassInfo( FIELD_HANDLER_TYPE_NAME );
|
||||
if ( ( typeName.charAt( 0 ) == 'L' )
|
||||
&& ( typeName.charAt( typeName.length() - 1 ) == ';' )
|
||||
|| ( typeName.charAt( 0 ) == '[' ) ) {
|
||||
// reference type
|
||||
final int indexOfL = typeName.indexOf( 'L' );
|
||||
String type;
|
||||
if ( indexOfL == 0 ) {
|
||||
// not array
|
||||
type = typeName.substring( 1, typeName.length() - 1 );
|
||||
type = type.replace( '/', '.' );
|
||||
}
|
||||
else if ( indexOfL == -1 ) {
|
||||
// array of primitive type
|
||||
// do nothing
|
||||
type = typeName;
|
||||
}
|
||||
else {
|
||||
// array of reference type
|
||||
type = typeName.replace( '/', '.' );
|
||||
}
|
||||
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readObject",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
4
|
||||
);
|
||||
// checkcast
|
||||
code.addCheckcast( type );
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeObject",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
5
|
||||
);
|
||||
// checkcast
|
||||
code.addCheckcast( type );
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "Z" ) ) {
|
||||
// boolean
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readBoolean",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;Z)Z",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeBoolean",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;ZZ)Z",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "B" ) ) {
|
||||
// byte
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readByte",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;B)B",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeByte",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;BB)B",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "C" ) ) {
|
||||
// char
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readChar",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;C)C",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeChar",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;CC)C",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "I" ) ) {
|
||||
// int
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readInt",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;I)I",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeInt",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;II)I",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "S" ) ) {
|
||||
// short
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readShort",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;S)S",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeShort",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;SS)S",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "D" ) ) {
|
||||
// double
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readDouble",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;D)D",
|
||||
5
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeDouble",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;DD)D",
|
||||
7
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "F" ) ) {
|
||||
// float
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readFloat",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;F)F",
|
||||
4
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeFloat",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;FF)F",
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( typeName.equals( "J" ) ) {
|
||||
// long
|
||||
if ( isReadMethod ) {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"readLong",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;J)J",
|
||||
5
|
||||
);
|
||||
}
|
||||
else {
|
||||
code.addInvokeinterface(
|
||||
callbackTypeIndex,
|
||||
"writeLong",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;JJ)J",
|
||||
7
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// bad type
|
||||
throw new RuntimeException( "bad type: " + typeName );
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTypeDependDataLoad(Bytecode code, String typeName, int i) {
|
||||
if ( typeName.charAt( 0 ) == 'L'
|
||||
&& typeName.charAt( typeName.length() - 1 ) == ';'
|
||||
|| typeName.charAt( 0 ) == '[' ) {
|
||||
// reference type
|
||||
code.addAload( i );
|
||||
}
|
||||
else if ( typeName.equals( "Z" )
|
||||
|| typeName.equals( "B" )
|
||||
|| typeName.equals( "C" )
|
||||
|| typeName.equals( "I" )
|
||||
|| typeName.equals( "S" ) ) {
|
||||
// boolean, byte, char, int, short
|
||||
code.addIload( i );
|
||||
}
|
||||
else if ( typeName.equals( "D" ) ) {
|
||||
// double
|
||||
code.addDload( i );
|
||||
}
|
||||
else if ( typeName.equals( "F" ) ) {
|
||||
// float
|
||||
code.addFload( i );
|
||||
}
|
||||
else if ( typeName.equals( "J" ) ) {
|
||||
// long
|
||||
code.addLload( i );
|
||||
}
|
||||
else {
|
||||
// bad type
|
||||
throw new RuntimeException( "bad type: " + typeName );
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTypeDependDataStore(Bytecode code, String typeName, int i) {
|
||||
if ( typeName.charAt( 0 ) == 'L'
|
||||
&& typeName.charAt( typeName.length() - 1 ) == ';'
|
||||
|| typeName.charAt( 0 ) == '[' ) {
|
||||
// reference type
|
||||
code.addAstore( i );
|
||||
}
|
||||
else if ( typeName.equals( "Z" )
|
||||
|| typeName.equals( "B" )
|
||||
|| typeName.equals( "C" )
|
||||
|| typeName.equals( "I" )
|
||||
|| typeName.equals( "S" ) ) {
|
||||
// boolean, byte, char, int, short
|
||||
code.addIstore( i );
|
||||
}
|
||||
else if ( typeName.equals( "D" ) ) {
|
||||
// double
|
||||
code.addDstore( i );
|
||||
}
|
||||
else if ( typeName.equals( "F" ) ) {
|
||||
// float
|
||||
code.addFstore( i );
|
||||
}
|
||||
else if ( typeName.equals( "J" ) ) {
|
||||
// long
|
||||
code.addLstore( i );
|
||||
}
|
||||
else {
|
||||
// bad type
|
||||
throw new RuntimeException( "bad type: " + typeName );
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTypeDependDataReturn(Bytecode code, String typeName) {
|
||||
if ( typeName.charAt( 0 ) == 'L'
|
||||
&& typeName.charAt( typeName.length() - 1 ) == ';'
|
||||
|| typeName.charAt( 0 ) == '[') {
|
||||
// reference type
|
||||
code.addOpcode( Opcode.ARETURN );
|
||||
}
|
||||
else if ( typeName.equals( "Z" )
|
||||
|| typeName.equals( "B" )
|
||||
|| typeName.equals( "C" )
|
||||
|| typeName.equals( "I" )
|
||||
|| typeName.equals( "S" ) ) {
|
||||
// boolean, byte, char, int, short
|
||||
code.addOpcode( Opcode.IRETURN );
|
||||
}
|
||||
else if ( typeName.equals( "D" ) ) {
|
||||
// double
|
||||
code.addOpcode( Opcode.DRETURN );
|
||||
}
|
||||
else if ( typeName.equals( "F" ) ) {
|
||||
// float
|
||||
code.addOpcode( Opcode.FRETURN );
|
||||
}
|
||||
else if ( typeName.equals( "J" ) ) {
|
||||
// long
|
||||
code.addOpcode( Opcode.LRETURN );
|
||||
}
|
||||
else {
|
||||
// bad type
|
||||
throw new RuntimeException( "bad type: " + typeName );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.bytecode.ClassFile;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.buildtime.spi.ClassFilter;
|
||||
import org.hibernate.bytecode.spi.AbstractClassTransformerImpl;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Enhance the classes allowing them to implements InterceptFieldEnabled
|
||||
* This interface is then used by Hibernate for some optimizations.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
* @author Steve Ebersole
|
||||
* @author Dustin Schultz
|
||||
*/
|
||||
public class JavassistClassTransformer extends AbstractClassTransformerImpl {
|
||||
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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] doTransform(
|
||||
ClassLoader loader,
|
||||
String className,
|
||||
Class classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
ClassFile classfile;
|
||||
try {
|
||||
// WARNING: classfile only
|
||||
classfile = new ClassFile( new DataInputStream( new ByteArrayInputStream( classfileBuffer ) ) );
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.unableToBuildEnhancementMetamodel( className );
|
||||
return classfileBuffer;
|
||||
}
|
||||
|
||||
final ClassPool cp = new ClassPool();
|
||||
cp.appendSystemPath();
|
||||
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 );
|
||||
}
|
||||
|
||||
final FieldTransformer transformer = getFieldTransformer( classfile, cp );
|
||||
if ( transformer != null ) {
|
||||
LOG.debugf( "Enhancing %s", className );
|
||||
|
||||
DataOutputStream out = null;
|
||||
try {
|
||||
transformer.transform( classfile );
|
||||
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
out = new DataOutputStream( byteStream );
|
||||
classfile.write( out );
|
||||
return byteStream.toByteArray();
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return classfileBuffer;
|
||||
}
|
||||
|
||||
protected FieldTransformer getFieldTransformer(final ClassFile classfile, final ClassPool classPool) {
|
||||
if ( alreadyInstrumented( classfile ) ) {
|
||||
return null;
|
||||
}
|
||||
return new FieldTransformer(
|
||||
new FieldFilter() {
|
||||
public boolean handleRead(String desc, String name) {
|
||||
return fieldFilter.shouldInstrumentField( classfile.getName(), name );
|
||||
}
|
||||
|
||||
public boolean handleWrite(String desc, String name) {
|
||||
return fieldFilter.shouldInstrumentField( classfile.getName(), name );
|
||||
}
|
||||
|
||||
public boolean handleReadAccess(String fieldOwnerClassName, String fieldName) {
|
||||
return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName );
|
||||
}
|
||||
|
||||
public boolean handleWriteAccess(String fieldOwnerClassName, String fieldName) {
|
||||
return fieldFilter.shouldTransformFieldAccess( classfile.getName(), fieldOwnerClassName, fieldName );
|
||||
}
|
||||
},
|
||||
classPool
|
||||
);
|
||||
}
|
||||
|
||||
private boolean alreadyInstrumented(ClassFile classfile) {
|
||||
final String[] interfaces = classfile.getInterfaces();
|
||||
for ( String anInterface : interfaces ) {
|
||||
if ( FieldHandled.class.getName().equals( anInterface ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.internal.javassist;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
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;
|
||||
|
||||
TransformingClassLoader(ClassLoader parent, String[] classpaths) {
|
||||
this.parent = parent;
|
||||
this.classPool = new ClassPool( true );
|
||||
for ( String classpath : classpaths ) {
|
||||
try {
|
||||
classPool.appendClassPath( classpath );
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
throw new HibernateException(
|
||||
"Unable to resolve requested classpath for transformation [" +
|
||||
classpath + "] : " + e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class findClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
final CtClass cc = classPool.get( name );
|
||||
// todo : modify the class definition if not already transformed...
|
||||
final 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;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.spi.ClassFilter;
|
||||
import org.hibernate.bytecode.buildtime.spi.FieldFilter;
|
||||
|
||||
/**
|
||||
* Basic implementation of the {@link ClassTransformer} contract.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractClassTransformerImpl implements ClassTransformer {
|
||||
protected final ClassFilter classFilter;
|
||||
protected final FieldFilter fieldFilter;
|
||||
|
||||
protected AbstractClassTransformerImpl(ClassFilter classFilter, FieldFilter fieldFilter) {
|
||||
this.classFilter = classFilter;
|
||||
this.fieldFilter = fieldFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(
|
||||
ClassLoader loader,
|
||||
String className,
|
||||
Class classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
// to be safe...
|
||||
className = className.replace( '/', '.' );
|
||||
if ( classFilter.shouldInstrumentClass( className ) ) {
|
||||
return doTransform( loader, className, classBeingRedefined, protectionDomain, classfileBuffer );
|
||||
}
|
||||
else {
|
||||
return classfileBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
Class classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Encapsulates bytecode enhancement information about a particular entity.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BytecodeEnhancementMetadata {
|
||||
/**
|
||||
* The name of the entity to which this metadata applies.
|
||||
*
|
||||
* @return The entity name
|
||||
*/
|
||||
String getEntityName();
|
||||
|
||||
/**
|
||||
* Has the entity class been bytecode enhanced for lazy loading?
|
||||
*
|
||||
* @return {@code true} indicates the entity class is enhanced for Hibernate use
|
||||
* in lazy loading; {@code false} indicates it is not
|
||||
*/
|
||||
boolean isEnhancedForLazyLoading();
|
||||
|
||||
/**
|
||||
* Build and inject an interceptor instance into the enhanced entity.
|
||||
*
|
||||
* @param entity The entity into which built interceptor should be injected
|
||||
* @param uninitializedFieldNames The name of fields marked as lazy
|
||||
* @param session The session to which the entity instance belongs.
|
||||
*
|
||||
* @return The built and injected interceptor
|
||||
*
|
||||
* @throws NotInstrumentedException Thrown if {@link #isEnhancedForLazyLoading()} returns {@code false}
|
||||
*/
|
||||
LazyAttributeLoadingInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
Set<String> uninitializedFieldNames,
|
||||
SessionImplementor session) throws NotInstrumentedException;
|
||||
|
||||
/**
|
||||
* Extract the field interceptor instance from the enhanced entity.
|
||||
*
|
||||
* @param entity The entity from which to extract the interceptor
|
||||
*
|
||||
* @return The extracted interceptor
|
||||
*
|
||||
* @throws NotInstrumentedException Thrown if {@link #isEnhancedForLazyLoading()} returns {@code false}
|
||||
*/
|
||||
LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException;
|
||||
}
|
|
@ -6,16 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.spi.ClassFilter;
|
||||
import org.hibernate.bytecode.buildtime.spi.FieldFilter;
|
||||
|
||||
/**
|
||||
* Contract for providers of bytecode services to Hibernate.
|
||||
* <p/>
|
||||
* Bytecode requirements break down into basically 3 areas<ol>
|
||||
* Bytecode requirements break down into the following areas<ol>
|
||||
* <li>proxy generation (both for runtime-lazy-loading and basic proxy generation) {@link #getProxyFactoryFactory()}</li>
|
||||
* <li>bean reflection optimization {@link #getReflectionOptimizer}</li>
|
||||
* <li>field-access instrumentation {@link #getTransformer}</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
|
@ -27,7 +23,7 @@ public interface BytecodeProvider {
|
|||
*
|
||||
* @return The provider specific factory.
|
||||
*/
|
||||
public ProxyFactoryFactory getProxyFactoryFactory();
|
||||
ProxyFactoryFactory getProxyFactoryFactory();
|
||||
|
||||
/**
|
||||
* Retrieve the ReflectionOptimizer delegate for this provider
|
||||
|
@ -39,26 +35,5 @@ public interface BytecodeProvider {
|
|||
* @param types The types of all properties to be accessed.
|
||||
* @return The reflection optimization delegate.
|
||||
*/
|
||||
public ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types);
|
||||
|
||||
/**
|
||||
* Generate a ClassTransformer capable of performing bytecode manipulation.
|
||||
*
|
||||
* @param classFilter filter used to limit which classes are to be instrumented
|
||||
* via this ClassTransformer.
|
||||
* @param fieldFilter filter used to limit which fields are to be instrumented
|
||||
* via this ClassTransformer.
|
||||
* @return The appropriate ClassTransformer.
|
||||
*/
|
||||
public ClassTransformer getTransformer(ClassFilter classFilter, FieldFilter fieldFilter);
|
||||
|
||||
/**
|
||||
* Retrieve the interception metadata for the particular entity type.
|
||||
*
|
||||
* @param entityClass The entity class. Note: we pass class here instead of the usual "entity name" because
|
||||
* only real classes can be instrumented.
|
||||
*
|
||||
* @return The metadata
|
||||
*/
|
||||
public EntityInstrumentationMetadata getEntityInstrumentationMetadata(Class entityClass);
|
||||
ReflectionOptimizer getReflectionOptimizer(Class clazz, String[] getterNames, String[] setterNames, Class[] types);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
|
@ -18,21 +19,22 @@ import java.security.ProtectionDomain;
|
|||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public interface ClassTransformer {
|
||||
public interface ClassTransformer extends javax.persistence.spi.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 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
|
||||
*/
|
||||
@Override
|
||||
public byte[] transform(
|
||||
ClassLoader loader,
|
||||
String classname,
|
||||
Class classBeingRedefined,
|
||||
String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer);
|
||||
byte[] classfileBuffer) throws IllegalClassFormatException;
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.bytecode.spi;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Encapsulates bytecode instrumentation information about a particular entity.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EntityInstrumentationMetadata {
|
||||
/**
|
||||
* The name of the entity to which this metadata applies.
|
||||
*
|
||||
* @return The entity name
|
||||
*/
|
||||
public String getEntityName();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param uninitializedFieldNames The name of fields marked as lazy
|
||||
* @param session The session to which the entity instance belongs.
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Extract the field interceptor instance from the instrumented entity.
|
||||
*
|
||||
* @param entity The entity from which to extract the interceptor
|
||||
*
|
||||
* @return The extracted interceptor
|
||||
*
|
||||
* @throws NotInstrumentedException Thrown if {@link #isInstrumented()} returns {@code false}
|
||||
*/
|
||||
public FieldInterceptor extractInterceptor(Object entity) throws NotInstrumentedException;
|
||||
}
|
|
@ -16,7 +16,6 @@ import org.hibernate.EntityMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityEntryExtraState;
|
||||
|
@ -279,13 +278,6 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
getPersister().setPropertyValue( entity, getPersister().getVersionProperty(), nextVersion );
|
||||
}
|
||||
|
||||
if ( getPersister().getInstrumentationMetadata().isInstrumented() ) {
|
||||
final FieldInterceptor interceptor = getPersister().getInstrumentationMetadata().extractInterceptor( entity );
|
||||
if ( interceptor != null ) {
|
||||
interceptor.clearDirty();
|
||||
}
|
||||
}
|
||||
|
||||
if( entity instanceof SelfDirtinessTracker ) {
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
|
@ -340,7 +332,7 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
|
||||
@SuppressWarnings( {"SimplifiableIfStatement"})
|
||||
private boolean isUnequivocallyNonDirty(Object entity) {
|
||||
if (entity instanceof SelfDirtinessTracker) {
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
return ! ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||
}
|
||||
|
||||
|
@ -354,11 +346,6 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( getPersister().getInstrumentationMetadata().isInstrumented() ) {
|
||||
// the entity must be instrumented (otherwise we cant check dirty flag) and the dirty flag is false
|
||||
return ! getPersister().getInstrumentationMetadata().extractInterceptor( entity ).isDirty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.io.Serializable;
|
|||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.Iterator;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.CascadingActions;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.hibernate.NonUniqueObjectException;
|
|||
import org.hibernate.PersistentObjectException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
|
@ -226,8 +226,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
// todo : I dont think this need be reentrant safe
|
||||
if ( objectEntityEntryEntry.getKey() instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) objectEntityEntryEntry.getKey() ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof LazyAttributeLoader ) {
|
||||
( (LazyAttributeLoader) interceptor ).unsetSession();
|
||||
if ( interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
( (LazyAttributeLoadingInterceptor) interceptor ).unsetSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.hibernate.AssertionFailure;
|
|||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.entry.CacheEntry;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.NonUniqueObjectException;
|
|||
import org.hibernate.action.internal.AbstractEntityInsertAction;
|
||||
import org.hibernate.action.internal.EntityIdentityInsertAction;
|
||||
import org.hibernate.action.internal.EntityInsertAction;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
import org.hibernate.engine.internal.Cascade;
|
||||
import org.hibernate.engine.internal.CascadePoint;
|
||||
|
@ -288,8 +287,6 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent
|
|||
insert.handleNaturalIdPostSaveNotifications( id );
|
||||
}
|
||||
|
||||
markInterceptorDirty( entity, persister, source );
|
||||
|
||||
EntityEntry newEntry = source.getPersistenceContext().getEntry( entity );
|
||||
|
||||
if ( newEntry != original ) {
|
||||
|
@ -327,18 +324,6 @@ public abstract class AbstractSaveEventListener extends AbstractReassociateEvent
|
|||
}
|
||||
}
|
||||
|
||||
private void markInterceptorDirty(Object entity, EntityPersister persister, EventSource source) {
|
||||
if ( persister.getInstrumentationMetadata().isInstrumented() ) {
|
||||
FieldInterceptor interceptor = persister.getInstrumentationMetadata().injectInterceptor(
|
||||
entity,
|
||||
persister.getEntityName(),
|
||||
null,
|
||||
source
|
||||
);
|
||||
interceptor.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
protected Map getMergeMap(Object anything) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package org.hibernate.event.internal;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
|
|
@ -217,12 +217,8 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
if ( event.getEntityEntry().getPersister().getInstrumentationMetadata().isInstrumented() ) {
|
||||
event.getEntityEntry()
|
||||
.getPersister()
|
||||
.getInstrumentationMetadata()
|
||||
.extractInterceptor( event.getEntity() )
|
||||
.clearDirty();
|
||||
if ( SelfDirtinessTracker.class.isInstance( event.getEntity() ) ) {
|
||||
( (SelfDirtinessTracker) event.getEntity() ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
event.getSession()
|
||||
.getFactory()
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.ObjectDeletedException;
|
|||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.internal.Cascade;
|
||||
import org.hibernate.engine.internal.CascadePoint;
|
||||
|
@ -336,13 +335,6 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
|
|||
}
|
||||
|
||||
private void markInterceptorDirty(final Object entity, final Object target, EntityPersister persister) {
|
||||
if ( persister.getInstrumentationMetadata().isInstrumented() ) {
|
||||
FieldInterceptor interceptor = persister.getInstrumentationMetadata().extractInterceptor( target );
|
||||
if ( interceptor != null ) {
|
||||
interceptor.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
// for enhanced entities, copy over the dirty attributes
|
||||
if ( entity instanceof SelfDirtinessTracker && target instanceof SelfDirtinessTracker ) {
|
||||
// clear, because setting the embedded attributes dirties them
|
||||
|
|
|
@ -201,12 +201,12 @@ public interface DeprecationLogger extends BasicLogger {
|
|||
)
|
||||
void logDeprecatedTransactionFactorySetting(String legacySettingName, String updatedSettingName);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id = 90000019,
|
||||
value = "You are using the deprecated legacy bytecode enhancement feature which has been superseded by a vastly improved bytecode enhancer."
|
||||
)
|
||||
void logDeprecatedBytecodeEnhancement();
|
||||
// @LogMessage(level = WARN)
|
||||
// @Message(
|
||||
// id = 90000019,
|
||||
// value = "You are using the deprecated legacy bytecode enhancement feature which has been superseded by a vastly improved bytecode enhancer."
|
||||
// )
|
||||
// void logDeprecatedBytecodeEnhancement();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
|
|
|
@ -33,10 +33,9 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.entry.CacheEntry;
|
||||
|
@ -66,8 +65,6 @@ import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.engine.spi.PersistenceContext.NaturalIdHelper;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.ValueInclusion;
|
||||
|
@ -577,7 +574,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// PROPERTIES
|
||||
|
||||
final boolean lazyAvailable = isInstrumented() || entityMetamodel.isLazyLoadingBytecodeEnhanced();
|
||||
final boolean lazyAvailable = isInstrumented();
|
||||
|
||||
int hydrateSpan = entityMetamodel.getPropertySpan();
|
||||
propertyColumnSpans = new int[hydrateSpan];
|
||||
|
@ -4244,27 +4241,17 @@ public abstract class AbstractEntityPersister
|
|||
// }
|
||||
|
||||
public void afterReassociate(Object entity, SessionImplementor session) {
|
||||
if ( getEntityMetamodel().getInstrumentationMetadata().isInstrumented() ) {
|
||||
FieldInterceptor interceptor = getEntityMetamodel().getInstrumentationMetadata()
|
||||
.extractInterceptor( entity );
|
||||
if ( interceptor != null ) {
|
||||
interceptor.setSession( session );
|
||||
}
|
||||
else {
|
||||
FieldInterceptor fieldInterceptor = getEntityMetamodel().getInstrumentationMetadata().injectInterceptor(
|
||||
if ( getEntityMetamodel().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) {
|
||||
LazyAttributeLoadingInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata().extractInterceptor( entity );
|
||||
if ( interceptor == null ) {
|
||||
getEntityMetamodel().getBytecodeEnhancementMetadata().injectInterceptor(
|
||||
entity,
|
||||
getEntityName(),
|
||||
null,
|
||||
session
|
||||
);
|
||||
fieldInterceptor.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoader ) {
|
||||
( (LazyAttributeLoader) interceptor ).setSession( session );
|
||||
else {
|
||||
interceptor.setSession( session );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4378,7 +4365,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
public boolean hasProxy() {
|
||||
// skip proxy instantiation if entity is bytecode enhanced
|
||||
return entityMetamodel.isLazy() && !entityMetamodel.isLazyLoadingBytecodeEnhanced();
|
||||
return entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
}
|
||||
|
||||
public IdentifierGenerator getIdentifierGenerator() throws HibernateException {
|
||||
|
@ -4477,7 +4464,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
public boolean isInstrumented() {
|
||||
return entityMetamodel.isInstrumented();
|
||||
return entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
}
|
||||
|
||||
public boolean hasInsertGeneratedProperties() {
|
||||
|
@ -5101,8 +5088,8 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityInstrumentationMetadata getInstrumentationMetadata() {
|
||||
return entityMetamodel.getInstrumentationMetadata();
|
||||
public BytecodeEnhancementMetadata getInstrumentationMetadata() {
|
||||
return entityMetamodel.getBytecodeEnhancementMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cache.spi.OptimisticCacheSource;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
|
@ -779,7 +779,7 @@ public interface EntityPersister extends OptimisticCacheSource, EntityDefinition
|
|||
public EntityMode getEntityMode();
|
||||
public EntityTuplizer getEntityTuplizer();
|
||||
|
||||
public EntityInstrumentationMetadata getInstrumentationMetadata();
|
||||
public BytecodeEnhancementMetadata getInstrumentationMetadata();
|
||||
|
||||
public FilterAliasGenerator getFilterAliasGenerator(final String rootAlias);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.lang.reflect.Method;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.PropertyAccessException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -41,8 +41,8 @@ public class EnhancedGetterMethodImpl implements Getter {
|
|||
private boolean isAttributeLoaded(Object owner) {
|
||||
if ( owner instanceof PersistentAttributeInterceptable ) {
|
||||
PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) owner ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoader ) {
|
||||
return ( (LazyAttributeLoader) interceptor ).isAttributeLoaded( propertyName );
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
return ( (LazyAttributeLoadingInterceptor) interceptor ).isAttributeLoaded( propertyName );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.tool.instrument;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.spi.Instrumenter;
|
||||
import org.hibernate.bytecode.buildtime.spi.Logger;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
|
||||
/**
|
||||
* Super class for all Hibernate instrumentation tasks. Provides the basic templating of how instrumentation
|
||||
* should occur; subclasses simply plug in to that process appropriately for the given bytecode provider.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class BasicInstrumentationTask extends Task implements Instrumenter.Options {
|
||||
|
||||
private final LoggerBridge logger = new LoggerBridge();
|
||||
|
||||
private List filesets = new ArrayList();
|
||||
private boolean extended;
|
||||
|
||||
// deprecated option...
|
||||
private boolean verbose;
|
||||
|
||||
public void addFileset(FileSet set) {
|
||||
this.filesets.add( set );
|
||||
}
|
||||
|
||||
protected final Iterator filesets() {
|
||||
return filesets.iterator();
|
||||
}
|
||||
|
||||
public boolean isExtended() {
|
||||
return extended;
|
||||
}
|
||||
|
||||
public void setExtended(boolean extended) {
|
||||
this.extended = extended;
|
||||
}
|
||||
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public final boolean performExtendedInstrumentation() {
|
||||
return isExtended();
|
||||
}
|
||||
|
||||
protected abstract Instrumenter buildInstrumenter(Logger logger, Instrumenter.Options options);
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
try {
|
||||
buildInstrumenter( logger, this )
|
||||
.execute( collectSpecifiedFiles() );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new BuildException( t );
|
||||
}
|
||||
}
|
||||
|
||||
private Set collectSpecifiedFiles() {
|
||||
HashSet files = new HashSet();
|
||||
Project project = getProject();
|
||||
Iterator filesets = filesets();
|
||||
while ( filesets.hasNext() ) {
|
||||
FileSet fs = ( FileSet ) filesets.next();
|
||||
DirectoryScanner ds = fs.getDirectoryScanner( project );
|
||||
String[] includedFiles = ds.getIncludedFiles();
|
||||
File d = fs.getDir( project );
|
||||
for ( int i = 0; i < includedFiles.length; ++i ) {
|
||||
files.add( new File( d, includedFiles[i] ) );
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
protected class LoggerBridge implements Logger {
|
||||
public void trace(String message) {
|
||||
log( message, Project.MSG_VERBOSE );
|
||||
}
|
||||
|
||||
public void debug(String message) {
|
||||
log( message, Project.MSG_DEBUG );
|
||||
}
|
||||
|
||||
public void info(String message) {
|
||||
log( message, Project.MSG_INFO );
|
||||
}
|
||||
|
||||
public void warn(String message) {
|
||||
log( message, Project.MSG_WARN );
|
||||
}
|
||||
|
||||
public void error(String message) {
|
||||
log( message, Project.MSG_ERR );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.tool.instrument.javassist;
|
||||
|
||||
import org.hibernate.bytecode.buildtime.internal.JavassistInstrumenter;
|
||||
import org.hibernate.bytecode.buildtime.spi.Instrumenter;
|
||||
import org.hibernate.bytecode.buildtime.spi.Logger;
|
||||
import org.hibernate.tool.instrument.BasicInstrumentationTask;
|
||||
|
||||
/**
|
||||
* An Ant task for instrumenting persistent classes in order to enable
|
||||
* field-level interception using Javassist.
|
||||
* <p/>
|
||||
* In order to use this task, typically you would define a a taskdef
|
||||
* similiar to:<pre>
|
||||
* <taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
|
||||
* <classpath refid="lib.class.path"/>
|
||||
* </taskdef>
|
||||
* </pre>
|
||||
* where <tt>lib.class.path</tt> is an ANT path reference containing all the
|
||||
* required Hibernate and Javassist libraries.
|
||||
* <p/>
|
||||
* And then use it like:<pre>
|
||||
* <instrument verbose="true">
|
||||
* <fileset dir="${testclasses.dir}/org/hibernate/test">
|
||||
* <include name="yadda/yadda/**"/>
|
||||
* ...
|
||||
* </fileset>
|
||||
* </instrument>
|
||||
* </pre>
|
||||
* where the nested ANT fileset includes the class you would like to have
|
||||
* instrumented.
|
||||
* <p/>
|
||||
* Optionally you can chose to enable "Extended Instrumentation" if desired
|
||||
* by specifying the extended attriubute on the task:<pre>
|
||||
* <instrument verbose="true" extended="true">
|
||||
* ...
|
||||
* </instrument>
|
||||
* </pre>
|
||||
* See the Hibernate manual regarding this option.
|
||||
*
|
||||
* @author Muga Nishizawa
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InstrumentTask extends BasicInstrumentationTask {
|
||||
@Override
|
||||
protected Instrumenter buildInstrumenter(Logger logger, Instrumenter.Options options) {
|
||||
return new JavassistInstrumenter( logger, options );
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>
|
||||
The <tt>instrument</tt> tool for adding field-interception hooks
|
||||
to persistent classes using built-time bytecode processing. Use
|
||||
this tool only if you wish to take advantage of lazy property
|
||||
fetching (the <tt><lazy></tt> mapping element).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -14,7 +14,7 @@ import java.util.Set;
|
|||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -153,7 +153,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
|||
|
||||
instantiator = buildInstantiator( mappingInfo );
|
||||
|
||||
if ( entityMetamodel.isLazy() && !entityMetamodel.isLazyLoadingBytecodeEnhanced() ) {
|
||||
if ( entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) {
|
||||
proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
|
||||
if ( proxyFactory == null ) {
|
||||
entityMetamodel.setLazy( false );
|
||||
|
@ -657,7 +657,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
|||
|
||||
@Override
|
||||
public boolean hasProxy() {
|
||||
return entityMetamodel.isLazy() && !entityMetamodel.isLazyLoadingBytecodeEnhanced();
|
||||
return entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.tuple.entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.bytecode.spi.NotInstrumentedException;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BytecodeEnhancementMetadataNonEnhancedPojoImpl implements BytecodeEnhancementMetadata {
|
||||
private final Class entityClass;
|
||||
private final String errorMsg;
|
||||
|
||||
public BytecodeEnhancementMetadataNonEnhancedPojoImpl(Class entityClass) {
|
||||
this.entityClass = entityClass;
|
||||
this.errorMsg = "Entity class [" + entityClass.getName() + "] is not enhanced";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return entityClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnhancedForLazyLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyAttributeLoadingInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
Set<String> uninitializedFieldNames,
|
||||
SessionImplementor session) throws NotInstrumentedException {
|
||||
throw new NotInstrumentedException( errorMsg );
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException {
|
||||
throw new NotInstrumentedException( errorMsg );
|
||||
}
|
||||
}
|
|
@ -8,19 +8,19 @@ package org.hibernate.tuple.entity;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.bytecode.spi.NotInstrumentedException;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NonPojoInstrumentationMetadata implements EntityInstrumentationMetadata {
|
||||
public class BytecodeEnhancementMetadataNonPojoImpl implements BytecodeEnhancementMetadata {
|
||||
private final String entityName;
|
||||
private final String errorMsg;
|
||||
|
||||
public NonPojoInstrumentationMetadata(String entityName) {
|
||||
public BytecodeEnhancementMetadataNonPojoImpl(String entityName) {
|
||||
this.entityName = entityName;
|
||||
this.errorMsg = "Entity [" + entityName + "] is non-pojo, and therefore not instrumented";
|
||||
}
|
||||
|
@ -31,19 +31,20 @@ public class NonPojoInstrumentationMetadata implements EntityInstrumentationMeta
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstrumented() {
|
||||
public boolean isEnhancedForLazyLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor extractInterceptor(Object entity) throws NotInstrumentedException {
|
||||
public LazyAttributeLoadingInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
Set<String> uninitializedFieldNames,
|
||||
SessionImplementor session) throws NotInstrumentedException {
|
||||
throw new NotInstrumentedException( errorMsg );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldInterceptor injectInterceptor(
|
||||
Object entity, String entityName, Set uninitializedFieldNames, SessionImplementor session)
|
||||
throws NotInstrumentedException {
|
||||
public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException {
|
||||
throw new NotInstrumentedException( errorMsg );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.tuple.entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.bytecode.spi.NotInstrumentedException;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementMetadata {
|
||||
private final Class entityClass;
|
||||
private final boolean enhancedForLazyLoading;
|
||||
|
||||
public BytecodeEnhancementMetadataPojoImpl(Class entityClass) {
|
||||
this.entityClass = entityClass;
|
||||
this.enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( entityClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return entityClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnhancedForLazyLoading() {
|
||||
return enhancedForLazyLoading;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException {
|
||||
if ( !enhancedForLazyLoading ) {
|
||||
throw new NotInstrumentedException( "Entity class [" + entityClass.getName() + "] is not enhanced for lazy loading" );
|
||||
}
|
||||
|
||||
if ( !entityClass.isInstance( entity ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Passed entity instance [%s] is not of expected type [%s]",
|
||||
entity,
|
||||
getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (LazyAttributeLoadingInterceptor) interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyAttributeLoadingInterceptor injectInterceptor(
|
||||
Object entity,
|
||||
Set<String> uninitializedFieldNames,
|
||||
SessionImplementor session) throws NotInstrumentedException {
|
||||
if ( !enhancedForLazyLoading ) {
|
||||
throw new NotInstrumentedException( "Entity class [" + entityClass.getName() + "] is not enhanced for lazy loading" );
|
||||
}
|
||||
|
||||
if ( !entityClass.isInstance( entity ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Passed entity instance [%s] is not of expected type [%s]",
|
||||
entity,
|
||||
getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final LazyAttributeLoadingInterceptor interceptor = new LazyAttributeLoadingInterceptor( session, uninitializedFieldNames, getEntityName() );
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
return interceptor;
|
||||
}
|
||||
}
|
|
@ -18,13 +18,11 @@ import java.util.Set;
|
|||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.CascadeStyles;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.ValueInclusion;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
@ -124,8 +122,7 @@ public class EntityMetamodel implements Serializable {
|
|||
|
||||
private final EntityMode entityMode;
|
||||
private final EntityTuplizer entityTuplizer;
|
||||
private final EntityInstrumentationMetadata instrumentationMetadata;
|
||||
private final boolean lazyLoadingBytecodeEnhanced;
|
||||
private final BytecodeEnhancementMetadata bytecodeEnhancementMetadata;
|
||||
|
||||
public EntityMetamodel(
|
||||
PersistentClass persistentClass,
|
||||
|
@ -145,12 +142,12 @@ public class EntityMetamodel implements Serializable {
|
|||
|
||||
versioned = persistentClass.isVersioned();
|
||||
|
||||
instrumentationMetadata = persistentClass.hasPojoRepresentation()
|
||||
? Environment.getBytecodeProvider().getEntityInstrumentationMetadata( persistentClass.getMappedClass() )
|
||||
: new NonPojoInstrumentationMetadata( persistentClass.getEntityName() );
|
||||
|
||||
lazyLoadingBytecodeEnhanced = ( persistentClass.getMappedClass() != null
|
||||
&& PersistentAttributeInterceptable.class.isAssignableFrom( persistentClass.getMappedClass() ) );
|
||||
if ( persistentClass.hasPojoRepresentation() ) {
|
||||
bytecodeEnhancementMetadata = new BytecodeEnhancementMetadataPojoImpl( persistentClass.getMappedClass() );
|
||||
}
|
||||
else {
|
||||
bytecodeEnhancementMetadata = new BytecodeEnhancementMetadataNonPojoImpl( persistentClass.getEntityName() );
|
||||
}
|
||||
|
||||
boolean hasLazy = false;
|
||||
|
||||
|
@ -201,7 +198,7 @@ public class EntityMetamodel implements Serializable {
|
|||
sessionFactory,
|
||||
i,
|
||||
prop,
|
||||
instrumentationMetadata.isInstrumented()
|
||||
bytecodeEnhancementMetadata.isEnhancedForLazyLoading()
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -210,7 +207,7 @@ public class EntityMetamodel implements Serializable {
|
|||
sessionFactory,
|
||||
i,
|
||||
prop,
|
||||
instrumentationMetadata.isInstrumented()
|
||||
bytecodeEnhancementMetadata.isEnhancedForLazyLoading()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -226,7 +223,7 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
|
||||
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
boolean lazy = prop.isLazy() && ( instrumentationMetadata.isInstrumented() || lazyLoadingBytecodeEnhanced );
|
||||
boolean lazy = prop.isLazy() && bytecodeEnhancementMetadata.isEnhancedForLazyLoading();
|
||||
if ( lazy ) {
|
||||
hasLazy = true;
|
||||
}
|
||||
|
@ -1096,14 +1093,10 @@ public class EntityMetamodel implements Serializable {
|
|||
* Whether or not this class can be lazy (ie intercepted)
|
||||
*/
|
||||
public boolean isInstrumented() {
|
||||
return instrumentationMetadata.isInstrumented();
|
||||
return bytecodeEnhancementMetadata.isEnhancedForLazyLoading();
|
||||
}
|
||||
|
||||
public EntityInstrumentationMetadata getInstrumentationMetadata() {
|
||||
return instrumentationMetadata;
|
||||
}
|
||||
|
||||
public boolean isLazyLoadingBytecodeEnhanced() {
|
||||
return this.lazyLoadingBytecodeEnhanced;
|
||||
public BytecodeEnhancementMetadata getBytecodeEnhancementMetadata() {
|
||||
return bytecodeEnhancementMetadata;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,7 @@ import org.hibernate.EntityMode;
|
|||
import org.hibernate.EntityNameResolver;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
|
||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
|
@ -57,14 +55,14 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
private final boolean lifecycleImplementor;
|
||||
private final Set<String> lazyPropertyNames;
|
||||
private final ReflectionOptimizer optimizer;
|
||||
private final boolean isInstrumented;
|
||||
private final boolean isBytecodeEnhanced;
|
||||
|
||||
public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
|
||||
super( entityMetamodel, mappedEntity );
|
||||
this.mappedClass = mappedEntity.getMappedClass();
|
||||
this.proxyInterface = mappedEntity.getProxyInterface();
|
||||
this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass );
|
||||
this.isInstrumented = entityMetamodel.isInstrumented();
|
||||
this.isBytecodeEnhanced = entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
|
||||
Iterator iter = mappedEntity.getPropertyClosureIterator();
|
||||
Set<String> tmpLazyPropertyNames = new HashSet<String>( );
|
||||
|
@ -284,23 +282,15 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
|
||||
@Override
|
||||
public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
|
||||
if ( isInstrumented() ) {
|
||||
Set<String> lazyProps = lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties() ?
|
||||
lazyPropertyNames : null;
|
||||
//TODO: if we support multiple fetch groups, we would need
|
||||
// to clone the set of lazy properties!
|
||||
FieldInterceptionHelper.injectFieldInterceptor( entity, getEntityName(), lazyProps, session );
|
||||
}
|
||||
|
||||
// new bytecode enhancement lazy interception
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
if ( lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties() ) {
|
||||
PersistentAttributeInterceptor interceptor = new LazyAttributeLoader( session, lazyPropertyNames, getEntityName() );
|
||||
PersistentAttributeInterceptor interceptor = new LazyAttributeLoadingInterceptor( session, lazyPropertyNames, getEntityName() );
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( interceptor );
|
||||
}
|
||||
}
|
||||
|
||||
//also clear the fields that are marked as dirty in the dirtyness tracker
|
||||
// also clear the fields that are marked as dirty in the dirtyness tracker
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||
}
|
||||
|
@ -311,21 +301,18 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
if ( getEntityMetamodel().hasLazyProperties() ) {
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoader ) {
|
||||
return ( (LazyAttributeLoader) interceptor ).isUninitialized();
|
||||
if ( interceptor != null && interceptor instanceof LazyAttributeLoadingInterceptor ) {
|
||||
return ( (LazyAttributeLoadingInterceptor) interceptor ).hasAnyUninitializedAttributes();
|
||||
}
|
||||
}
|
||||
FieldInterceptor callback = FieldInterceptionHelper.extractFieldInterceptor( entity );
|
||||
return callback != null && !callback.isInitialized();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstrumented() {
|
||||
return isInstrumented;
|
||||
return isBytecodeEnhanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.type;
|
|||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import org.hibernate.testing.ServiceRegistryBuilder;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestTask;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.enhancement;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
import org.hibernate.engine.spi.CompositeTracker;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
import com.sun.tools.classfile.ConstantPoolException;
|
||||
import com.sun.tools.javap.JavapTask;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* utility class to use in bytecode enhancement tests
|
||||
*
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
public abstract class DecompileUtils {
|
||||
|
||||
private static final CoreMessageLogger log = CoreLogging.messageLogger( DecompileUtils.class );
|
||||
|
||||
public static void decompileDumpedClass(String workingDir, String className) {
|
||||
try {
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
|
||||
fileManager.setLocation(
|
||||
StandardLocation.CLASS_OUTPUT,
|
||||
Collections.singletonList( new File( workingDir ) )
|
||||
);
|
||||
|
||||
JavapTask javapTask = new JavapTask();
|
||||
String filename = workingDir + File.separator + getFilenameForClassName( className );
|
||||
for ( JavaFileObject jfo : fileManager.getJavaFileObjects( filename ) ) {
|
||||
try {
|
||||
Set<String> interfaceNames = new HashSet<String>();
|
||||
Set<String> fieldNames = new HashSet<String>();
|
||||
Set<String> methodNames = new HashSet<String>();
|
||||
|
||||
JavapTask.ClassFileInfo info = javapTask.read( jfo );
|
||||
|
||||
log.infof( "decompiled class [%s]", info.cf.getName() );
|
||||
|
||||
for ( int i : info.cf.interfaces ) {
|
||||
interfaceNames.add( info.cf.constant_pool.getClassInfo( i ).getName() );
|
||||
log.debugf( "declared iFace = ", info.cf.constant_pool.getClassInfo( i ).getName() );
|
||||
}
|
||||
for ( com.sun.tools.classfile.Field f : info.cf.fields ) {
|
||||
fieldNames.add( f.getName( info.cf.constant_pool ) );
|
||||
log.debugf( "declared field = ", f.getName( info.cf.constant_pool ) );
|
||||
}
|
||||
for ( com.sun.tools.classfile.Method m : info.cf.methods ) {
|
||||
methodNames.add( m.getName( info.cf.constant_pool ) );
|
||||
log.debugf( "declared method = ", m.getName( info.cf.constant_pool ) );
|
||||
}
|
||||
|
||||
// checks signature against known interfaces
|
||||
if ( interfaceNames.contains( PersistentAttributeInterceptor.class.getName() ) ) {
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.INTERCEPTOR_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_GETTER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.INTERCEPTOR_SETTER_NAME ) );
|
||||
}
|
||||
if ( interfaceNames.contains( ManagedEntity.class.getName() ) ) {
|
||||
assertTrue( methodNames.contains( EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME ) );
|
||||
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.ENTITY_ENTRY_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_GETTER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.ENTITY_ENTRY_SETTER_NAME ) );
|
||||
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.PREVIOUS_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_GETTER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.PREVIOUS_SETTER_NAME ) );
|
||||
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.NEXT_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.NEXT_GETTER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.NEXT_SETTER_NAME ) );
|
||||
}
|
||||
if ( interfaceNames.contains( SelfDirtinessTracker.class.getName() ) ) {
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_GET_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CLEAR_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_HAS_CHANGED_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_SUSPEND_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COLLECTION_GET_NAME ) );
|
||||
}
|
||||
if ( interfaceNames.contains( CompositeTracker.class.getName() ) ) {
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER ) );
|
||||
}
|
||||
if ( interfaceNames.contains( CompositeOwner.class.getName() ) ) {
|
||||
assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) );
|
||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) );
|
||||
}
|
||||
}
|
||||
catch (ConstantPoolException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
assertNull( "Failed to open class file", ioe );
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
log.warnf( re, "WARNING: UNABLE DECOMPILE DUE TO %s", re.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFilenameForClassName(String className) {
|
||||
return className.replace( '.', File.separatorChar ) + JavaFileObject.Kind.CLASS.extension;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ package org.hibernate.test.bytecode.enhancement;
|
|||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.test.bytecode.enhancement.association.ManyToManyAssociationTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.association.OneToManyAssociationTestTask;
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.hibernate.test.bytecode.enhancement.association;
|
|||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hibernate.engine.spi.ManagedEntity;
|
|||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.net.URLClassLoader;
|
|||
import org.hibernate.Session;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
|
|
|
@ -13,7 +13,7 @@ import javax.persistence.Id;
|
|||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ import javax.persistence.OneToMany;
|
|||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.test.bytecode.enhancement.basic.ObjectAttributeMarkerInterceptor;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.test.bytecode.enhancement.lazy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
@ -17,8 +16,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,7 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,6 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
|
@ -26,7 +25,7 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
|
||||
import org.hibernate.test.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.bytecode.spi.EntityInstrumentationMetadata;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
|
||||
|
@ -47,7 +47,7 @@ import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
|||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
||||
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.VersionType;
|
||||
|
@ -87,8 +87,8 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityInstrumentationMetadata getInstrumentationMetadata() {
|
||||
return new NonPojoInstrumentationMetadata( null );
|
||||
public BytecodeEnhancementMetadata getInstrumentationMetadata() {
|
||||
return new BytecodeEnhancementMetadataNonPojoImpl( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.buildtime;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
|
||||
import org.hibernate.test.instrument.cases.Executable;
|
||||
import org.hibernate.test.instrument.cases.TestCustomColumnReadAndWrite;
|
||||
import org.hibernate.test.instrument.cases.TestDirtyCheckExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestFetchAllExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyBasicFieldAccessExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyBasicPropertyAccessExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestSharedPKOneToOneExecutable;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.testing.Skip;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
@Skip(
|
||||
message = "domain classes not instrumented for build-time instrumentation testing",
|
||||
condition = InstrumentTest.SkipCheck.class
|
||||
)
|
||||
public class InstrumentTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
public void testDirtyCheck() throws Exception {
|
||||
execute( new TestDirtyCheckExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchAll() throws Exception {
|
||||
execute( new TestFetchAllExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazy() throws Exception {
|
||||
execute( new TestLazyExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyManyToOne() throws Exception {
|
||||
execute( new TestLazyManyToOneExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFieldInterceptor() throws Exception {
|
||||
execute( new TestInjectFieldInterceptorExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertyInitialized() throws Exception {
|
||||
execute( new TestIsPropertyInitializedExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToOneProxy() throws Exception {
|
||||
execute( new TestManyToOneProxyExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyPropertyCustomTypeExecutable() throws Exception {
|
||||
execute( new TestLazyPropertyCustomTypeExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyBasicFieldAccess() throws Exception {
|
||||
execute( new TestLazyBasicFieldAccessExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyBasicPropertyAccess() throws Exception {
|
||||
execute( new TestLazyBasicPropertyAccessExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSharedPKOneToOne() throws Exception {
|
||||
execute( new TestSharedPKOneToOneExecutable() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomColumnReadAndWrite() throws Exception {
|
||||
execute( new TestCustomColumnReadAndWrite() );
|
||||
}
|
||||
|
||||
private void execute(Executable executable) throws Exception {
|
||||
executable.prepare();
|
||||
try {
|
||||
executable.execute();
|
||||
}
|
||||
finally {
|
||||
executable.complete();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SkipCheck implements Skip.Matcher {
|
||||
@Override
|
||||
public boolean isMatch() {
|
||||
return ! FieldInterceptionHelper.isInstrumented( new Document() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.spi.InstrumentedClassLoader;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractExecutable implements Executable {
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private SessionFactory factory;
|
||||
|
||||
@Override
|
||||
public final void prepare() {
|
||||
BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder();
|
||||
// make sure we pick up the TCCL, and make sure its the isolated CL...
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == null ) {
|
||||
throw new RuntimeException( "Isolated ClassLoader not yet set as TCCL" );
|
||||
}
|
||||
if ( !InstrumentedClassLoader.class.isInstance( classLoader ) ) {
|
||||
throw new RuntimeException( "Isolated ClassLoader not yet set as TCCL" );
|
||||
}
|
||||
bsrb.applyClassLoader( classLoader );
|
||||
|
||||
serviceRegistry = new StandardServiceRegistryBuilder( bsrb.build() )
|
||||
.applySetting( Environment.HBM2DDL_AUTO, "create-drop" )
|
||||
.build();
|
||||
|
||||
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
||||
for ( String resource : getResources() ) {
|
||||
metadataSources.addResource( resource );
|
||||
}
|
||||
|
||||
factory = metadataSources.buildMetadata().buildSessionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void complete() {
|
||||
try {
|
||||
cleanup();
|
||||
}
|
||||
finally {
|
||||
factory.close();
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
protected SessionFactory getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
}
|
||||
|
||||
protected String[] getResources() {
|
||||
return new String[] { "org/hibernate/test/instrument/domain/Documents.hbm.xml" };
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Executable {
|
||||
public void prepare();
|
||||
public void execute() throws Exception;
|
||||
public void complete();
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Rob.Hasselbaum
|
||||
*/
|
||||
public class TestCustomColumnReadAndWrite extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
final double SIZE_IN_KB = 20480;
|
||||
final double SIZE_IN_MB = SIZE_IN_KB / 1024d;
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName("gavin");
|
||||
doc.setName("Hibernate in Action");
|
||||
doc.setSummary("blah");
|
||||
doc.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
doc.setOwner(o);
|
||||
doc.setFolder(fol);
|
||||
doc.setSizeKb(SIZE_IN_KB);
|
||||
fol.getDocuments().add(doc);
|
||||
s.persist(o);
|
||||
s.persist(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
|
||||
// Check value conversion on insert
|
||||
// Value returned by Oracle native query is a Types.NUMERIC, which is mapped to a BigDecimalType;
|
||||
// Cast returned value to Number then call Number.doubleValue() so it works on all dialects.
|
||||
Double sizeViaSql =
|
||||
( (Number)s.createSQLQuery("select size_mb from documents").uniqueResult() )
|
||||
.doubleValue();
|
||||
assertEquals( SIZE_IN_MB, sizeViaSql, 0.01d );
|
||||
|
||||
// Test explicit fetch of all properties
|
||||
doc = (Document) s.createQuery("from Document fetch all properties").uniqueResult();
|
||||
assertTrue( Hibernate.isPropertyInitialized( doc, "sizeKb" ) );
|
||||
assertEquals( SIZE_IN_KB, doc.getSizeKb() );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
// Test lazy fetch with custom read
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.get( Document.class, doc.getId() );
|
||||
assertFalse( Hibernate.isPropertyInitialized( doc, "sizeKb" ) );
|
||||
assertEquals( SIZE_IN_KB, doc.getSizeKb() );
|
||||
s.delete(doc);
|
||||
s.delete( doc.getOwner() );
|
||||
s.delete( doc.getFolder() );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestDirtyCheckExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Folder pics = new Folder();
|
||||
pics.setName("pics");
|
||||
Folder docs = new Folder();
|
||||
docs.setName("docs");
|
||||
s.persist(docs);
|
||||
s.persist(pics);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
List list = s.createCriteria(Folder.class).list();
|
||||
for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
|
||||
Folder f = (Folder) iter.next();
|
||||
Assert.assertFalse( f.nameWasread );
|
||||
}
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
for ( Iterator iter = list.iterator(); iter.hasNext(); ) {
|
||||
Folder f = (Folder) iter.next();
|
||||
Assert.assertFalse( f.nameWasread );
|
||||
}
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
s.createQuery("delete from Folder").executeUpdate();
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestFetchAllExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName("gavin");
|
||||
doc.setName("Hibernate in Action");
|
||||
doc.setSummary("blah");
|
||||
doc.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
doc.setOwner(o);
|
||||
doc.setFolder(fol);
|
||||
fol.getDocuments().add(doc);
|
||||
s.persist(o);
|
||||
s.persist(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document fetch all properties").uniqueResult();
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "owner" ) );
|
||||
Assert.assertEquals( doc.getSummary(), "blah" );
|
||||
s.delete(doc);
|
||||
s.delete( doc.getOwner() );
|
||||
s.delete( doc.getFolder() );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.spi.InstrumentedClassLoader;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import org.hibernate.testing.ServiceRegistryBuilder;
|
||||
import org.hibernate.test.instrument.domain.Passport;
|
||||
import org.hibernate.test.instrument.domain.Person;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestFetchingLazyToOneExecutable implements Executable {
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private SessionFactory factory;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
doBaselineAssertions();
|
||||
|
||||
doFetchNonMappedBySideAssertions();
|
||||
doFetchMappedBySideAssertions();
|
||||
}
|
||||
|
||||
private void doBaselineAssertions() {
|
||||
{
|
||||
// First, load from the non-owning side by id. Person#passport should be uninitialized
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
Person person = (Person) s.get( Person.class, 1 );
|
||||
assertTrue( Hibernate.isInitialized( person ) );
|
||||
assertFalse( Hibernate.isPropertyInitialized( person, "passport" ) );
|
||||
assertNotNull( person.getPassport() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
{
|
||||
// Then, load from the owning side by id. Passport#person should be uninitialized
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
Passport passport = (Passport) s.get( Passport.class, 1 );
|
||||
assertTrue( Hibernate.isInitialized( passport ) );
|
||||
assertFalse( Hibernate.isPropertyInitialized( passport, "person" ) );
|
||||
assertNotNull( passport.getPerson() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void doFetchNonMappedBySideAssertions() {
|
||||
// try to eagerly fetch the association from the owning (non-mappedBy) side
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// the whole question here is design, and whether the `fetch all properties` should be needed
|
||||
// Passport p = (Passport) s.createQuery( "select p from Passport p join fetch p.person" ).uniqueResult();
|
||||
// versus:
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Passport p = (Passport) s.createQuery( "select p from Passport p fetch all properties join fetch p.person" ).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( p ) );
|
||||
assertTrue(
|
||||
"Assertion that the eager fetch of non-mappedBy association (Passport#person) was performed properly",
|
||||
Hibernate.isPropertyInitialized( p, "person" )
|
||||
);
|
||||
assertNotNull( p.getPerson() );
|
||||
assertTrue( Hibernate.isInitialized( p.getPerson() ) );
|
||||
assertSame( p, p.getPerson().getPassport() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
private void doFetchMappedBySideAssertions() {
|
||||
// try to eagerly fetch the association from the non-owning (mappedBy) side
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// the whole question here is design, and whether the `fetch all properties` should be needed
|
||||
// Person p = (Person) s.createQuery( "select p from Person p join fetch p.passport" ).uniqueResult();
|
||||
// versus:
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Person p = (Person) s.createQuery( "select p from Person p fetch all properties join fetch p.passport" ).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( p ) );
|
||||
assertTrue(
|
||||
"Assertion that the eager fetch of mappedBy association (Person#passport) was performed properly",
|
||||
Hibernate.isPropertyInitialized( p, "passport" )
|
||||
);
|
||||
assertNotNull( p.getPassport() );
|
||||
assertTrue( Hibernate.isInitialized( p.getPassport() ) );
|
||||
assertSame( p, p.getPassport().getPerson() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void prepare() {
|
||||
BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder();
|
||||
// make sure we pick up the TCCL, and make sure its the isolated CL...
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == null ) {
|
||||
throw new RuntimeException( "Isolated ClassLoader not yet set as TCCL" );
|
||||
}
|
||||
if ( !InstrumentedClassLoader.class.isInstance( classLoader ) ) {
|
||||
throw new RuntimeException( "Isolated ClassLoader not yet set as TCCL" );
|
||||
}
|
||||
bsrb.applyClassLoader( classLoader );
|
||||
|
||||
serviceRegistry = new StandardServiceRegistryBuilder( bsrb.build() )
|
||||
.applySetting( Environment.HBM2DDL_AUTO, "create-drop" )
|
||||
.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" )
|
||||
.build();
|
||||
|
||||
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
||||
metadataSources.addAnnotatedClass( Person.class );
|
||||
metadataSources.addAnnotatedClass( Passport.class );
|
||||
|
||||
factory = metadataSources.buildMetadata().buildSessionFactory();
|
||||
|
||||
createData();
|
||||
}
|
||||
|
||||
private void createData() {
|
||||
Person steve = new Person( "Steve" );
|
||||
Passport passport = new Passport( steve, "123456789", "Acme Emirates" );
|
||||
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
s.save( steve );
|
||||
s.save( passport );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void complete() {
|
||||
try {
|
||||
cleanupData();
|
||||
}
|
||||
finally {
|
||||
factory.close();
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupData() {
|
||||
Session s = factory.openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete Passport" ).executeUpdate();
|
||||
s.createQuery( "delete Person" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
|
||||
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestInjectFieldInterceptorExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Document doc = new Document();
|
||||
FieldInterceptionHelper.injectFieldInterceptor( doc, "Document", new HashSet(), null );
|
||||
doc.getId();
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
//$Id: $
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestIsPropertyInitializedExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName("gavin");
|
||||
doc.setName("Hibernate in Action");
|
||||
doc.setSummary("blah");
|
||||
doc.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
doc.setOwner(o);
|
||||
doc.setFolder(fol);
|
||||
fol.getDocuments().add(doc);
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
|
||||
s.persist(o);
|
||||
s.persist(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "summary" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "upperCaseName" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( doc, "owner" ) );
|
||||
s.delete(doc);
|
||||
s.delete( doc.getOwner() );
|
||||
s.delete( doc.getFolder() );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
package org.hibernate.test.instrument.cases;
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Andrei Ivanov
|
||||
*/
|
||||
public class TestLazyBasicFieldAccessExecutable extends AbstractExecutable {
|
||||
protected String[] getResources() {
|
||||
return new String[] {"org/hibernate/test/instrument/domain/Documents.hbm.xml"};
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName( "gavin" );
|
||||
doc.setName( "Hibernate in Action" );
|
||||
doc.setSummary( "blah" );
|
||||
doc.updateText( "blah blah" );
|
||||
fol.setName( "books" );
|
||||
doc.setOwner( o );
|
||||
doc.setFolder( fol );
|
||||
fol.getDocuments().add( doc );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
|
||||
s.persist( o );
|
||||
s.persist( fol );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// update with lazy property initialized
|
||||
doc.setName( "Doc Name" );
|
||||
doc.setSummary( "u" );
|
||||
s.update( doc );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// merge with lazy property initialized and updated
|
||||
doc.setName( "Doc Name 1" );
|
||||
doc.setSummary( "v" );
|
||||
Document docManaged = (Document) s.merge( doc );
|
||||
try {
|
||||
Assert.assertEquals("v", docManaged.getSummary());
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
s.getTransaction().rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge with lazy property initialized in doc; uninitialized in docManaged.
|
||||
doc.setSummary( "w" );
|
||||
Assert.assertSame( docManaged, s.merge( doc ) );
|
||||
Assert.assertEquals( "w", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// initialize docManaged.getSummary
|
||||
Assert.assertEquals( "w", docManaged.getSummary() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge with lazy property initialized in both doc and docManaged.
|
||||
doc.setSummary( "x" );
|
||||
Assert.assertSame( docManaged, s.merge( doc ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
Document docWithLazySummary = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// summary should still be uninitialized.
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
docWithLazySummary.setName( "new name" );
|
||||
// merge the Document with an uninitialized summary
|
||||
docManaged = (Document) s.merge( docWithLazySummary );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// initialize docManaged.getSummary
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge the Document with an uninitialized summary
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
docManaged = (Document) s.merge( docWithLazySummary );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
package org.hibernate.test.instrument.cases;
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Andrei Ivanov
|
||||
*/
|
||||
public class TestLazyBasicPropertyAccessExecutable extends AbstractExecutable {
|
||||
protected String[] getResources() {
|
||||
return new String[] {"org/hibernate/test/instrument/domain/DocumentsPropAccess.hbm.xml"};
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName( "gavin" );
|
||||
doc.setName( "Hibernate in Action" );
|
||||
doc.setSummary( "blah" );
|
||||
doc.updateText( "blah blah" );
|
||||
fol.setName( "books" );
|
||||
doc.setOwner( o );
|
||||
doc.setFolder( fol );
|
||||
fol.getDocuments().add( doc );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( doc, "summary" ) );
|
||||
s.persist( o );
|
||||
s.persist( fol );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// update with lazy property initialized
|
||||
doc.setName( "Doc Name" );
|
||||
doc.setSummary( "u" );
|
||||
s.update( doc );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// merge with lazy property initialized and updated
|
||||
doc.setName( "Doc Name 1" );
|
||||
doc.setSummary( "v" );
|
||||
Document docManaged = (Document) s.merge( doc );
|
||||
Assert.assertEquals( "v", docManaged.getSummary() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge with lazy property initialized in doc; uninitialized in docManaged.
|
||||
doc.setSummary( "w" );
|
||||
Assert.assertSame( docManaged, s.merge( doc ) );
|
||||
Assert.assertEquals( "w", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// initialize docManaged.getSummary
|
||||
Assert.assertEquals( "w", docManaged.getSummary() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge with lazy property initialized in both doc and docManaged.
|
||||
doc.setSummary( "x" );
|
||||
Assert.assertSame( docManaged, s.merge( doc ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
Document docWithLazySummary = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// summary should still be uninitialized.
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
docWithLazySummary.setName( "new name" );
|
||||
// merge the Document with an uninitialized summary
|
||||
docManaged = (Document) s.merge( docWithLazySummary );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
s.getTransaction().begin();
|
||||
// get the Document with an uninitialized summary
|
||||
docManaged = (Document) s.get( Document.class, doc.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// initialize docManaged.getSummary
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
// merge the Document with an uninitialized summary
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( docWithLazySummary, "summary" ) );
|
||||
docManaged = (Document) s.merge( docWithLazySummary );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( docManaged, "summary" ) );
|
||||
Assert.assertEquals( "x", docManaged.getSummary() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestLazyExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
// The following block is repeated 100 times to reproduce HHH-2627.
|
||||
// Without the fix, Oracle will run out of cursors using 10g with
|
||||
// a default installation (ORA-01000: maximum open cursors exceeded).
|
||||
// The number of loops may need to be adjusted depending on the how
|
||||
// Oracle is configured.
|
||||
// Note: The block is not indented to avoid a lot of irrelevant differences.
|
||||
for ( int i=0; i<100; i++ ) {
|
||||
|
||||
SessionFactory factory = getFactory();
|
||||
Session s = factory.openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName("gavin");
|
||||
doc.setName("Hibernate in Action");
|
||||
doc.setSummary("blah");
|
||||
doc.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
doc.setOwner(o);
|
||||
doc.setFolder(fol);
|
||||
fol.getDocuments().add(doc);
|
||||
s.save(o);
|
||||
s.save(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = ( Document ) s.get( Document.class, doc.getId() );
|
||||
TestCase.assertTrue( Hibernate.isPropertyInitialized(doc, "weirdProperty"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "folder"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner"));
|
||||
doc.getUpperCaseName(); // should force initialization
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "folder"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "owner"));
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
doc.getName();
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
doc.getName();
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary"));
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "summary"));
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
doc.setName("HiA");
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
TestCase.assertEquals( doc.getName(), "HiA" );
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
doc.getText();
|
||||
doc.setName("HiA second edition");
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "name"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "owner"));
|
||||
TestCase.assertEquals( doc.getName(), "HiA second edition" );
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
TestCase.assertEquals( doc.getUpperCaseName(), "HIA SECOND EDITION" );
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "weirdProperty"));
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "upperCaseName"));
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
s.lock(doc, LockMode.NONE);
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
doc.setName("HiA2");
|
||||
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
s.saveOrUpdate(doc);
|
||||
s.flush();
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertEquals( doc.getText(), "blah blah" );
|
||||
TestCase.assertTrue(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
doc.updateText("blah blah blah blah");
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = ( Document ) s.createQuery("from Document").uniqueResult();
|
||||
TestCase.assertEquals( doc.getName(), "HiA2" );
|
||||
TestCase.assertEquals( doc.getText(), "blah blah blah blah" );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.load( Document.class, doc.getId() );
|
||||
doc.getName();
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "text"));
|
||||
TestCase.assertFalse(Hibernate.isPropertyInitialized(doc, "summary"));
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = factory.openSession();
|
||||
s.setCacheMode( CacheMode.IGNORE );
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.createQuery("from Document").uniqueResult();
|
||||
//s.delete(doc);
|
||||
s.delete( doc.getFolder() );
|
||||
s.delete( doc.getOwner() );
|
||||
s.flush();
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestLazyManyToOneExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Owner gavin = new Owner();
|
||||
Document hia = new Document();
|
||||
Folder fol = new Folder();
|
||||
gavin.setName("gavin");
|
||||
hia.setName("Hibernate in Action");
|
||||
hia.setSummary("blah");
|
||||
hia.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
hia.setOwner(gavin);
|
||||
hia.setFolder(fol);
|
||||
fol.getDocuments().add(hia);
|
||||
s.persist(gavin);
|
||||
s.persist(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
hia = (Document) s.createCriteria(Document.class).uniqueResult();
|
||||
Assert.assertEquals( hia.getFolder().getClass(), Folder.class);
|
||||
fol = hia.getFolder();
|
||||
Assert.assertTrue( Hibernate.isInitialized(fol) );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
hia = (Document) s.createCriteria(Document.class).uniqueResult();
|
||||
Assert.assertSame( hia.getFolder(), s.load(Folder.class, fol.getId()) );
|
||||
Assert.assertTrue( Hibernate.isInitialized( hia.getFolder() ) );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
fol = (Folder) s.get(Folder.class, fol.getId());
|
||||
hia = (Document) s.createCriteria(Document.class).uniqueResult();
|
||||
Assert.assertSame( fol, hia.getFolder() );
|
||||
fol = hia.getFolder();
|
||||
Assert.assertTrue( Hibernate.isInitialized(fol) );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
fol = (Folder) s.load(Folder.class, fol.getId());
|
||||
hia = (Document) s.createCriteria(Document.class).uniqueResult();
|
||||
Assert.assertNotSame( fol, hia.getFolder() );
|
||||
fol = hia.getFolder();
|
||||
Assert.assertTrue( Hibernate.isInitialized(fol) );
|
||||
s.delete(hia.getFolder());
|
||||
s.delete(hia.getOwner());
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.bytecode.instrumentation.internal.FieldInterceptionHelper;
|
||||
|
||||
import org.hibernate.test.instrument.domain.Problematic;
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestLazyPropertyCustomTypeExecutable extends AbstractExecutable {
|
||||
|
||||
protected String[] getResources() {
|
||||
return new String[] { "org/hibernate/test/instrument/domain/Problematic.hbm.xml" };
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
Session s = getFactory().openSession();
|
||||
Problematic p = new Problematic();
|
||||
try {
|
||||
s.beginTransaction();
|
||||
p.setName( "whatever" );
|
||||
p.setBytes( new byte[] { 1, 0, 1, 1, 0 } );
|
||||
s.save( p );
|
||||
s.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
s.getTransaction().rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
|
||||
// this access should be ok because p1 is not a lazy proxy
|
||||
s = getFactory().openSession();
|
||||
try {
|
||||
s.beginTransaction();
|
||||
Problematic p1 = (Problematic) s.get( Problematic.class, p.getId() );
|
||||
Assert.assertTrue( FieldInterceptionHelper.isInstrumented( p1 ) );
|
||||
p1.getRepresentation();
|
||||
s.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
s.getTransaction().rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
|
||||
s = getFactory().openSession();
|
||||
try {
|
||||
s.beginTransaction();
|
||||
Problematic p1 = (Problematic) s.createQuery( "from Problematic" ).setReadOnly(true ).list().get( 0 );
|
||||
p1.getRepresentation();
|
||||
s.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
s.getTransaction().rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
|
||||
s = getFactory().openSession();
|
||||
try {
|
||||
s.beginTransaction();
|
||||
Problematic p1 = (Problematic) s.load( Problematic.class, p.getId() );
|
||||
Assert.assertFalse( FieldInterceptionHelper.isInstrumented( p1 ) );
|
||||
p1.setRepresentation( p.getRepresentation() );
|
||||
s.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
s.getTransaction().rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
Session s = getFactory().openSession();
|
||||
s.beginTransaction();
|
||||
Iterator itr = s.createQuery( "from Problematic" ).list().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
Problematic p = (Problematic) itr.next();
|
||||
s.delete( p );
|
||||
}
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.Entity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TestManyToOneProxyExecutable extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Entity root = new Entity( "root" );
|
||||
Entity child1 = new Entity( "child1" );
|
||||
Entity child2 = new Entity( "child2" );
|
||||
root.setChild( child1 );
|
||||
child1.setSibling( child2 );
|
||||
Entity gChild1 = new Entity( "grandchild 1" );
|
||||
Entity gChild2 = new Entity( "grandchild 2" );
|
||||
child1.setChild( gChild1 );
|
||||
gChild1.setSibling( gChild2 );
|
||||
s.save( root );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
// NOTE : child is mapped with lazy="proxy"; sibling with lazy="no-proxy"...
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
// load root
|
||||
root = ( Entity ) s.get( Entity.class, root.getId() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root, "child" ) );
|
||||
|
||||
// get a handle to the child1 proxy reference (and make certain that
|
||||
// this does not force the lazy properties of the root entity
|
||||
// to get initialized.
|
||||
child1 = root.getChild();
|
||||
Assert.assertFalse( Hibernate.isInitialized( child1 ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "sibling" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( child1, "child" ) );
|
||||
|
||||
child1.getName();
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "name" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "sibling" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( child1, "child" ) );
|
||||
|
||||
gChild1 = child1.getChild();
|
||||
Assert.assertFalse( Hibernate.isInitialized( gChild1 ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "sibling" ) );
|
||||
|
||||
s.delete( root );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.cases;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.test.instrument.domain.EntityWithOneToOnes;
|
||||
import org.hibernate.test.instrument.domain.OneToOneNoProxy;
|
||||
import org.hibernate.test.instrument.domain.OneToOneProxy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class TestSharedPKOneToOneExecutable extends AbstractExecutable {
|
||||
|
||||
protected String[] getResources() {
|
||||
return new String[] {"org/hibernate/test/instrument/domain/SharedPKOneToOne.hbm.xml"};
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
EntityWithOneToOnes root = new EntityWithOneToOnes( "root" );
|
||||
OneToOneProxy oneToOneProxy = new OneToOneProxy( "oneToOneProxy" );
|
||||
root.setOneToOneProxy( oneToOneProxy );
|
||||
oneToOneProxy.setEntity( root );
|
||||
OneToOneNoProxy oneToOneNoProxy = new OneToOneNoProxy( "oneToOneNoProxy" );
|
||||
root.setOneToOneNoProxy( oneToOneNoProxy );
|
||||
oneToOneNoProxy.setEntity( root );
|
||||
|
||||
s.save( root );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
// NOTE : oneToOneProxy is mapped with lazy="proxy"; oneToOneNoProxy with lazy="no-proxy"...
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
// load root
|
||||
root = ( EntityWithOneToOnes ) s.load( EntityWithOneToOnes.class, root.getId() );
|
||||
Assert.assertFalse( Hibernate.isInitialized( root ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "oneToOneProxy" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "oneToOneNoProxy" ) );
|
||||
|
||||
root.getName();
|
||||
Assert.assertTrue( Hibernate.isInitialized( root ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root, "name" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root, "oneToOneProxy" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "oneToOneNoProxy" ) );
|
||||
|
||||
// get a handle to the oneToOneProxy proxy reference (and make certain that
|
||||
// this does not force the lazy properties of the root entity
|
||||
// to get initialized.
|
||||
root.getOneToOneProxy();
|
||||
Assert.assertTrue( Hibernate.isInitialized( oneToOneProxy ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root.getOneToOneProxy(), "name" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( root, "oneToOneNoProxy" ) );
|
||||
|
||||
root.getOneToOneNoProxy();
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root, "oneToOneNoProxy" ) );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( root.getOneToOneNoProxy(), "name") );
|
||||
|
||||
s.delete( root );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* A simple byte[]-based custom type.
|
||||
*/
|
||||
public class CustomBlobType implements UserType {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object nullSafeGet(ResultSet rs, String names[], SessionImplementor session, Object owner) throws SQLException {
|
||||
// cast just to make sure...
|
||||
return StandardBasicTypes.BINARY.nullSafeGet( rs, names[0], session );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void nullSafeSet(PreparedStatement ps, Object value, int index, SessionImplementor session) throws SQLException, HibernateException {
|
||||
// cast just to make sure...
|
||||
StandardBasicTypes.BINARY.nullSafeSet( ps, value, index, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object deepCopy(Object value) {
|
||||
byte result[] = null;
|
||||
|
||||
if ( value != null ) {
|
||||
byte bytes[] = ( byte[] ) value;
|
||||
|
||||
result = new byte[bytes.length];
|
||||
System.arraycopy( bytes, 0, result, 0, bytes.length );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int[] sqlTypes() {
|
||||
return new int[] { Types.VARBINARY };
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Class returnedClass() {
|
||||
return byte[].class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean equals(Object x, Object y) {
|
||||
return Arrays.equals( ( byte[] ) x, ( byte[] ) y );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object assemble(Serializable arg0, Object arg1)
|
||||
throws HibernateException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Serializable disassemble(Object arg0)
|
||||
throws HibernateException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int hashCode(Object arg0)
|
||||
throws HibernateException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object replace(Object arg0, Object arg1, Object arg2)
|
||||
throws HibernateException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
//$Id: Document.java 9538 2006-03-04 00:17:57Z steve.ebersole@jboss.com $
|
||||
package org.hibernate.test.instrument.domain;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Document {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String upperCaseName;
|
||||
private String summary;
|
||||
private String text;
|
||||
private Owner owner;
|
||||
private Folder folder;
|
||||
private double sizeKb;
|
||||
private Date lastTextModification = new Date();
|
||||
/**
|
||||
* @return Returns the folder.
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
/**
|
||||
* @param folder The folder to set.
|
||||
*/
|
||||
public void setFolder(Folder folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
/**
|
||||
* @return Returns the owner.
|
||||
*/
|
||||
public Owner getOwner() {
|
||||
return owner;
|
||||
}
|
||||
/**
|
||||
* @param owner The owner to set.
|
||||
*/
|
||||
public void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* @return Returns the summary.
|
||||
*/
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
/**
|
||||
* @param summary The summary to set.
|
||||
*/
|
||||
public void setSummary(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
/**
|
||||
* @return Returns the text.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
/**
|
||||
* @param text The text to set.
|
||||
*/
|
||||
private void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
/**
|
||||
* @return Returns the upperCaseName.
|
||||
*/
|
||||
public String getUpperCaseName() {
|
||||
return upperCaseName;
|
||||
}
|
||||
/**
|
||||
* @param upperCaseName The upperCaseName to set.
|
||||
*/
|
||||
public void setUpperCaseName(String upperCaseName) {
|
||||
this.upperCaseName = upperCaseName;
|
||||
}
|
||||
/**
|
||||
* @param sizeKb The size in KBs.
|
||||
*/
|
||||
public void setSizeKb(double sizeKb) {
|
||||
this.sizeKb = sizeKb;
|
||||
}
|
||||
/**
|
||||
* @return The size in KBs.
|
||||
*/
|
||||
public double getSizeKb() {
|
||||
return sizeKb;
|
||||
}
|
||||
|
||||
public void updateText(String newText) {
|
||||
if ( !newText.equals(text) ) {
|
||||
this.text = newText;
|
||||
lastTextModification = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
This mapping demonstrates
|
||||
|
||||
(1) use of lazy properties - this feature requires buildtime
|
||||
bytecode instrumentation; we don't think this is a very
|
||||
necessary feature, but provide it for completeleness; if
|
||||
Hibernate encounters uninstrumented classes, lazy property
|
||||
fetching will be silently disabled, to enable testing
|
||||
|
||||
(2) use of a formula to define a "derived property"
|
||||
|
||||
-->
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.instrument.domain" default-access="field">
|
||||
|
||||
<class name="Folder" table="folders">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
<many-to-one name="parent"/>
|
||||
<bag name="subfolders" inverse="true" cascade="save-update">
|
||||
<key column="parent"/>
|
||||
<one-to-many class="Folder"/>
|
||||
</bag>
|
||||
<bag name="documents" inverse="true" cascade="all-delete-orphan">
|
||||
<key column="folder"/>
|
||||
<one-to-many class="Document"/>
|
||||
</bag>
|
||||
</class>
|
||||
|
||||
<class name="Owner" table="owners" lazy="false">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
</class>
|
||||
|
||||
<class name="Document" table="documents">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
<property name="upperCaseName" formula="upper(name)" lazy="true"/>
|
||||
<property name="summary" column="`summary`" not-null="true" length="200" lazy="true"/>
|
||||
<many-to-one name="folder" not-null="true" lazy="no-proxy"/>
|
||||
<many-to-one name="owner" not-null="true" lazy="no-proxy" fetch="select"/>
|
||||
<property name="text" not-null="true" length="2000" lazy="true"/>
|
||||
<property name="lastTextModification" not-null="true" lazy="true" access="field"/>
|
||||
<property name="sizeKb" lazy="true">
|
||||
<column name="size_mb"
|
||||
read="size_mb * 1024.0"
|
||||
write="? / cast( 1024.0 as float )"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
<class name="Entity" table="entity">
|
||||
<id name="id" column="ID" type="long">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" column="NAME" type="string" lazy="true"/>
|
||||
<many-to-one name="child" column="PRNT_ID" class="Entity" lazy="proxy" cascade="all" />
|
||||
<many-to-one name="sibling" column="RIGHT_ID" class="Entity" lazy="no-proxy" cascade="all" />
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
This mapping demonstrates
|
||||
|
||||
(1) use of lazy properties - this feature requires buildtime
|
||||
bytecode instrumentation; we don't think this is a very
|
||||
necessary feature, but provide it for completeleness; if
|
||||
Hibernate encounters uninstrumented classes, lazy property
|
||||
fetching will be silently disabled, to enable testing
|
||||
|
||||
(2) use of a formula to define a "derived property"
|
||||
|
||||
-->
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.instrument.domain" default-access="property">
|
||||
|
||||
<class name="Folder" table="folders">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
<many-to-one name="parent"/>
|
||||
<bag name="subfolders" inverse="true" cascade="save-update">
|
||||
<key column="parent"/>
|
||||
<one-to-many class="Folder"/>
|
||||
</bag>
|
||||
<bag name="documents" inverse="true" cascade="all-delete-orphan">
|
||||
<key column="folder"/>
|
||||
<one-to-many class="Document"/>
|
||||
</bag>
|
||||
</class>
|
||||
|
||||
<class name="Owner" table="owners" lazy="false">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
</class>
|
||||
|
||||
<class name="Document" table="documents">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
<property name="upperCaseName" formula="upper(name)" lazy="true"/>
|
||||
<property name="summary" column="`summary`" not-null="true" length="200" lazy="true"/>
|
||||
<many-to-one name="folder" not-null="true" lazy="no-proxy"/>
|
||||
<many-to-one name="owner" not-null="true" lazy="no-proxy" fetch="select"/>
|
||||
<property name="text" not-null="true" length="2000" lazy="true"/>
|
||||
<property name="lastTextModification" not-null="true" lazy="true" access="field"/>
|
||||
<property name="sizeKb" lazy="true">
|
||||
<column name="size_mb"
|
||||
read="size_mb * 1024.0"
|
||||
write="? / cast( 1024.0 as float )"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
<class name="Entity" table="entity">
|
||||
<id name="id" column="ID" type="long">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" column="NAME" type="string" lazy="true"/>
|
||||
<many-to-one name="child" column="PRNT_ID" class="Entity" lazy="proxy" cascade="all" />
|
||||
<many-to-one name="sibling" column="RIGHT_ID" class="Entity" lazy="no-proxy" cascade="all" />
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.domain;
|
||||
|
||||
|
||||
/**
|
||||
* todo: describe Entity
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class Entity {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Entity child;
|
||||
private Entity sibling;
|
||||
|
||||
public Entity() {
|
||||
}
|
||||
|
||||
public Entity(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Entity getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(Entity child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public Entity getSibling() {
|
||||
return sibling;
|
||||
}
|
||||
|
||||
public void setSibling(Entity sibling) {
|
||||
this.sibling = sibling;
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.instrument.domain;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityWithOneToOnes {
|
||||
private Long id;
|
||||
private String name;
|
||||
private OneToOneNoProxy oneToOneNoProxy;
|
||||
private OneToOneProxy oneToOneProxy;
|
||||
|
||||
public EntityWithOneToOnes() {
|
||||
}
|
||||
|
||||
public EntityWithOneToOnes(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public OneToOneNoProxy getOneToOneNoProxy() {
|
||||
return oneToOneNoProxy;
|
||||
}
|
||||
|
||||
public void setOneToOneNoProxy(OneToOneNoProxy oneToOneNoProxy) {
|
||||
this.oneToOneNoProxy = oneToOneNoProxy;
|
||||
}
|
||||
|
||||
public OneToOneProxy getOneToOneProxy() {
|
||||
return oneToOneProxy;
|
||||
}
|
||||
|
||||
public void setOneToOneProxy(OneToOneProxy oneToOneProxy) {
|
||||
this.oneToOneProxy = oneToOneProxy;
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
//$Id: Folder.java 9538 2006-03-04 00:17:57Z steve.ebersole@jboss.com $
|
||||
package org.hibernate.test.instrument.domain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Folder {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Folder parent;
|
||||
private Collection subfolders = new ArrayList();
|
||||
private Collection documents = new ArrayList();
|
||||
|
||||
public boolean nameWasread;
|
||||
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
nameWasread = true;
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* @return Returns the documents.
|
||||
*/
|
||||
public Collection getDocuments() {
|
||||
return documents;
|
||||
}
|
||||
/**
|
||||
* @param documents The documents to set.
|
||||
*/
|
||||
public void setDocuments(Collection documents) {
|
||||
this.documents = documents;
|
||||
}
|
||||
/**
|
||||
* @return Returns the parent.
|
||||
*/
|
||||
public Folder getParent() {
|
||||
return parent;
|
||||
}
|
||||
/**
|
||||
* @param parent The parent to set.
|
||||
*/
|
||||
public void setParent(Folder parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
/**
|
||||
* @return Returns the subfolders.
|
||||
*/
|
||||
public Collection getSubfolders() {
|
||||
return subfolders;
|
||||
}
|
||||
/**
|
||||
* @param subfolders The subfolders to set.
|
||||
*/
|
||||
public void setSubfolders(Collection subfolders) {
|
||||
this.subfolders = subfolders;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue