HHH-14792 Remove support for bytecode enhancement via Javassist

This commit is contained in:
Sanne Grinovero 2021-08-25 16:11:38 +01:00 committed by Sanne Grinovero
parent a70b994526
commit 9267c5e6a6
60 changed files with 16 additions and 4822 deletions

View File

@ -60,7 +60,6 @@
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle> <bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
<bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle> <bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle>
<bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle> <bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle>
<bundle>mvn:org.javassist/javassist/3.18.1-GA</bundle>
<bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle> <bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle>

View File

@ -56,9 +56,6 @@
org.apache.karaf.shell.console, org.apache.karaf.shell.console,
org.apache.karaf.shell.commands, org.apache.karaf.shell.commands,
javax.persistence;version="[1.0.0,2.1.0]", javax.persistence;version="[1.0.0,2.1.0]",
<!-- Needed for proxying's Javassist enhancement during runtime -->
org.hibernate.proxy,
javassist.util.proxy,
* *
</Import-Package> </Import-Package>
<Meta-Persistence>META-INF/persistence.xml</Meta-Persistence> <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>

View File

@ -33,7 +33,6 @@
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle> <bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
<bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle> <bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle>
<bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle> <bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle>
<bundle>mvn:org.javassist/javassist/3.18.1-GA</bundle>
<bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle> <bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle>

View File

@ -68,9 +68,6 @@
org.apache.karaf.shell.commands, org.apache.karaf.shell.commands,
org.h2, org.h2,
javax.persistence;version="[1.0.0,2.1.0]", javax.persistence;version="[1.0.0,2.1.0]",
<!-- Needed for proxying's Javassist enhancement during runtime -->
org.hibernate.proxy,
javassist.util.proxy,
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -41,7 +41,6 @@
<bundle>mvn:com.fasterxml/classmate/0.8.0</bundle> <bundle>mvn:com.fasterxml/classmate/0.8.0</bundle>
<bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle> <bundle>mvn:org.apache.logging.log4j/log4j-api/2.0</bundle>
<bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle> <bundle>mvn:org.jboss.logging/jboss-logging/3.2.1.Final</bundle>
<bundle>mvn:org.javassist/javassist/3.18.1-GA</bundle>
<bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle> <bundle>mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final</bundle>

View File

@ -76,9 +76,6 @@
org.hibernate.cfg, org.hibernate.cfg,
org.hibernate.service, org.hibernate.service,
javax.persistence;version="[1.0.0,2.1.0]", javax.persistence;version="[1.0.0,2.1.0]",
<!-- Needed for proxy enhancement during runtime -->
org.hibernate.proxy,
javassist.util.proxy,
* *
</Import-Package> </Import-Package>
</instructions> </instructions>

View File

@ -434,7 +434,7 @@ Enable lazy loading feature in runtime bytecode enhancement. This way, even basi
Enable association management feature in runtime bytecode enhancement which automatically synchronizes a bidirectional association when only one side is changed. Enable association management feature in runtime bytecode enhancement which automatically synchronizes a bidirectional association when only one side is changed.
`*hibernate.bytecode.provider*` (e.g. `bytebuddy` (default value)):: `*hibernate.bytecode.provider*` (e.g. `bytebuddy` (default value))::
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` and `javassist` are valid values; `bytebuddy` is the default and recommended choice; `javassist` will be removed soon. The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` is a valid value, as older deprecated options have been removed.
`*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value)):: `*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value))::
Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls. Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls.

View File

@ -455,10 +455,9 @@ Hibernate will trigger a Persistence Context flush if there are pending `Account
==== Define a custom entity proxy ==== Define a custom entity proxy
By default, when it needs to use a proxy instead of the actual POJO, Hibernate is going to use a Bytecode manipulation library like By default, when it needs to use a proxy instead of the actual POJO, Hibernate is going to use a Bytecode manipulation library like
https://jboss-javassist.github.io/javassist/[Javassist] or
https://bytebuddy.net/[Byte Buddy]. https://bytebuddy.net/[Byte Buddy].
However, if the entity class is final, Javassist will not create a proxy and you will get a POJO even when you only need a proxy reference. However, if the entity class is final, a proxy will not be created; you will get a POJO even when you only need a proxy reference.
In this case, you could proxy an interface that this particular entity implements, as illustrated by the following example. In this case, you could proxy an interface that this particular entity implements, as illustrated by the following example.
[[entity-proxy-interface-mapping]] [[entity-proxy-interface-mapping]]

View File

@ -93,7 +93,6 @@ That `DataSource` is then used by your `persistence.xml` persistence-unit. The f
Your bundle's manifest will need to import, at a minimum: Your bundle's manifest will need to import, at a minimum:
* `javax.persistence` * `javax.persistence`
* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime).
=== Obtaining an EntityManger === Obtaining an EntityManger
@ -123,7 +122,6 @@ Similar to any other JPA setup, your bundle must include a `persistence.xml` fil
Your bundle's manifest will need to import, at a minimum: Your bundle's manifest will need to import, at a minimum:
* `javax.persistence` * `javax.persistence`
* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime)
* JDBC driver package (example: `org.h2`) * JDBC driver package (example: `org.h2`)
* `org.osgi.framework`, necessary to discover the `EntityManagerFactory` (described below) * `org.osgi.framework`, necessary to discover the `EntityManagerFactory` (described below)
@ -157,7 +155,6 @@ Native Hibernate use is also supported. The client bundle is responsible for man
Your bundle's manifest will need to import, at a minimum: Your bundle's manifest will need to import, at a minimum:
* `javax.persistence` * `javax.persistence`
* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime)
* JDBC driver package (example: `org.h2`) * JDBC driver package (example: `org.h2`)
* `org.osgi.framework`, necessary to discover the `SessionFactory` (described below) * `org.osgi.framework`, necessary to discover the `SessionFactory` (described below)
* `org.hibernate.*` packages, as necessary (ex: cfg, criterion, service, etc.) * `org.hibernate.*` packages, as necessary (ex: cfg, criterion, service, etc.)

View File

@ -72,7 +72,6 @@ dependencies {
testCompile( libraries.byteman_bmunit ) testCompile( libraries.byteman_bmunit )
testRuntime( libraries.log4j2 ) testRuntime( libraries.log4j2 )
testRuntime( libraries.javassist )
testRuntime( libraries.byteBuddy ) testRuntime( libraries.byteBuddy )
//Databases //Databases

View File

@ -24,7 +24,6 @@ ext {
weldVersion = '3.1.5.Final' weldVersion = '3.1.5.Final'
jakartaWeldVersion = '4.0.1.SP1' jakartaWeldVersion = '4.0.1.SP1'
javassistVersion = '3.27.0-GA'
byteBuddyVersion = '1.11.12' byteBuddyVersion = '1.11.12'
agroalVersion = '1.9' agroalVersion = '1.9'
@ -64,9 +63,6 @@ ext {
// Dom4J // Dom4J
dom4j: 'org.dom4j:dom4j:2.1.3@jar', dom4j: 'org.dom4j:dom4j:2.1.3@jar',
// Javassist
javassist: "org.javassist:javassist:${javassistVersion}",
// Byte Buddy // Byte Buddy
byteBuddy: "net.bytebuddy:byte-buddy:${byteBuddyVersion}", byteBuddy: "net.bytebuddy:byte-buddy:${byteBuddyVersion}",

View File

@ -20,8 +20,6 @@ configurations {
dependencies { dependencies {
compile( libraries.jakarta_jpa ) compile( libraries.jakarta_jpa )
// This can now be made provided
compile( libraries.javassist )
// Could be made optional? // Could be made optional?
compile( libraries.byteBuddy ) compile( libraries.byteBuddy )
compile( libraries.antlr ) compile( libraries.antlr )
@ -75,7 +73,6 @@ dependencies {
testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" )
testRuntime( libraries.jakarta_el ) testRuntime( libraries.jakarta_el )
testRuntime( 'jaxen:jaxen:1.1' ) testRuntime( 'jaxen:jaxen:1.1' )
testRuntime( libraries.javassist )
testRuntime( libraries.byteBuddy ) testRuntime( libraries.byteBuddy )
testRuntime( libraries.jakarta_weld ) testRuntime( libraries.jakarta_weld )
testRuntime( libraries.atomikos ) testRuntime( libraries.atomikos )

View File

@ -28,31 +28,17 @@ sourceSets {
setSrcDirs( ['src/test/java','src/test/resources','src/test/bundles'] ) setSrcDirs( ['src/test/java','src/test/resources','src/test/bundles'] )
} }
} }
testJavassist {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
}
}
} }
configurations { configurations {
tests { tests {
description = 'Configuration for the produced test jar' description = 'Configuration for the produced test jar'
} }
//Configures the compile and runtime configurations for our javassist tests
//and includes the dependencies of the test task.
testJavassistCompile.extendsFrom testCompile
testJavassistRuntime.extendsFrom testRuntime
} }
dependencies { dependencies {
compile( libraries.jpa ) compile( libraries.jpa )
// This can now be made provided
compile( libraries.javassist )
// Could be made optional? // Could be made optional?
compile( libraries.byteBuddy ) compile( libraries.byteBuddy )
compile( libraries.antlr ) compile( libraries.antlr )
@ -103,7 +89,6 @@ dependencies {
testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" )
testRuntime( libraries.expression_language ) testRuntime( libraries.expression_language )
testRuntime( 'jaxen:jaxen:1.1' ) testRuntime( 'jaxen:jaxen:1.1' )
testRuntime( libraries.javassist )
testRuntime( libraries.byteBuddy ) testRuntime( libraries.byteBuddy )
testRuntime( libraries.weld ) testRuntime( libraries.weld )
testRuntime( libraries.atomikos ) testRuntime( libraries.atomikos )
@ -118,9 +103,6 @@ dependencies {
testCompile libraries.jboss_ejb_spec_jar testCompile libraries.jboss_ejb_spec_jar
testCompile libraries.jboss_annotation_spec_jar testCompile libraries.jboss_annotation_spec_jar
// Additional tests requiring Javassist
// folder in src/javassist/java
testJavassistCompile libraries.javassist
} }
jar { jar {
@ -265,35 +247,3 @@ test {
} }
} }
//Create the task that runs the integration tests found from the
//configured source directory and uses the correct classpath.
task testJavassist(type: Test) {
testClassesDirs = sourceSets.testJavassist.output.classesDirs
classpath = sourceSets.testJavassist.runtimeClasspath
//If you want to ensure that integration tests are run every time when you invoke
//this task, uncomment the following line.
//outputs.upToDateWhen { false }
if ( gradle.ext.javaToolchainEnabled ) {
// Configure version of Java tools
javaLauncher = javaToolchains.launcherFor {
languageVersion = gradle.ext.javaVersions.test.launcher
}
// Configure JVM Options
jvmArgs( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) )
// Display version of Java tools
doFirst {
logger.lifecycle "Testing javassist with '${javaLauncher.get().metadata.installationPath}'"
}
}
if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) {
// Javassist needs this to generate proxies
jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] )
}
}
check.dependsOn testJavassist
testJavassist.mustRunAfter test

View File

@ -1,279 +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.enhance.internal.javassist;
import java.util.Collection;
import java.util.Locale;
import java.util.Objects;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javassist.CtClass;
import javassist.CtField;
import javassist.NotFoundException;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
/**
* utility class to generate interceptor methods
* @see org.hibernate.engine.spi.PersistentAttributeInterceptor
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public abstract class AttributeTypeDescriptor {
protected InheritanceMetadata inheritanceMetadata;
protected AttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata) {
this.inheritanceMetadata = inheritanceMetadata;
}
public abstract String buildReadInterceptionBodyFragment(String fieldName);
public abstract String buildWriteInterceptionBodyFragment(String fieldName);
public String buildInLineDirtyCheckingBodyFragment(JavassistEnhancementContext context, CtField currentValue) {
StringBuilder builder = new StringBuilder();
try {
// should ignore primary keys
if ( PersistentAttributesHelper.hasAnnotation( currentValue, Id.class )
|| PersistentAttributesHelper.hasAnnotation( currentValue, EmbeddedId.class ) ) {
return "";
}
String readFragment = inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible()
? "super." + inheritanceMetadata.getReaderName() + "()"
: "this." + currentValue.getName();
if ( currentValue.getType().isPrimitive() || currentValue.getType().isEnum() ) {
// primitives || enums
builder.append( String.format( " if ( %s != $1 )", readFragment ) );
}
else {
// if the field is a collection we return since we handle that in a separate method
for ( CtClass ctClass : currentValue.getType().getInterfaces() ) {
if ( ctClass.getName().equals( Collection.class.getName() ) ) {
// if the collection is not managed we should write it to the tracker
if ( context.isMappedCollection( currentValue ) ) {
return "";
}
}
}
builder.append(
String.format(
" if ( !%s.deepEquals( %s, $1 ) )",
Objects.class.getName(),
readFragment
)
);
}
builder.append( String.format( " { %s(\"%s\"); }", EnhancerConstants.TRACKER_CHANGER_NAME, currentValue.getName() ) );
}
catch (NotFoundException ignore) {
}
return builder.toString();
}
/* --- */
/**
* factory method to get the AttributeTypeDescriptor for a particular field type
*/
public static AttributeTypeDescriptor resolve(CtClass managedCtClass, CtField persistentField) throws NotFoundException {
boolean inherited = !managedCtClass.equals( persistentField.getDeclaringClass() );
boolean visible = persistentField.visibleFrom( managedCtClass );
String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName();
String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + persistentField.getName();
InheritanceMetadata inheritanceMetadata = new InheritanceMetadata( inherited, visible, readerName, writerName );
if ( CtClass.booleanType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Boolean.TYPE );
}
else if ( CtClass.byteType.equals( persistentField.getType() )) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Byte.TYPE );
}
else if ( CtClass.charType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Character.TYPE );
}
else if ( CtClass.shortType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Short.TYPE );
}
else if ( CtClass.intType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Integer.TYPE );
}
else if ( CtClass.longType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Long.TYPE );
}
else if ( CtClass.doubleType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Double.TYPE );
}
else if ( CtClass.floatType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Float.TYPE );
}
else {
return new ObjectAttributeTypeDescriptor( inheritanceMetadata, persistentField.getType() );
}
}
/* --- */
/**
* AttributeTypeDescriptor for non primitive types
*/
private static class ObjectAttributeTypeDescriptor extends AttributeTypeDescriptor {
private final String type;
private ObjectAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, CtClass concreteType) {
super( inheritanceMetadata );
this.type = concreteType.getName();
}
@Override
public String buildReadInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" if( %3$s() != null ) { super.%5$s( (%2$s) %3$s().readObject(this, \"%1$s\", super.%4$s())); }%n",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" if ( %3$s() != null ) { this.%1$s = (%2$s) %3$s().readObject(this, \"%1$s\", this.%1$s); }%n",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
@Override
public String buildWriteInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", super.%4$s(), $1); }%n" +
" super.%5$s(localVar);",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", this.%1$s, $1); }%n" +
" this.%1$s = localVar;",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
}
/**
* AttributeTypeDescriptor for primitive types
*/
private static class PrimitiveAttributeTypeDescriptor extends AttributeTypeDescriptor {
private final String type;
private PrimitiveAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, Class<?> primitiveType) {
super( inheritanceMetadata );
if ( !primitiveType.isPrimitive() ) {
throw new IllegalArgumentException( "Primitive attribute type descriptor can only be used on primitive types" );
}
// capitalize first letter
this.type = primitiveType.getSimpleName().substring( 0, 1 ).toUpperCase( Locale.ROOT ) + primitiveType.getSimpleName().substring( 1 );
}
@Override
public String buildReadInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" if (%3$s() != null ) { super.%5$s( %3$s().read%2$s(this, \"%1$s\", super.%4$s())); }",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" if (%3$s() != null ) { this.%1$s = %3$s().read%2$s(this, \"%1$s\", this.%1$s); }",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
@Override
public String buildWriteInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", super.%5$s(), $1); }%n" +
" super.%6$s(localVar);",
fieldName,
type.toLowerCase( Locale.ROOT ),
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", this.%1$s, $1); }%n" +
" this.%1$s = localVar;",
fieldName,
type.toLowerCase( Locale.ROOT ),
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME
);
}
}
}
//
private static class InheritanceMetadata {
private boolean inherited;
private boolean visible;
private String readerName;
private String writerName;
public InheritanceMetadata(boolean inherited, boolean visible, String readerName, String writerName) {
this.inherited = inherited;
this.visible = visible;
this.readerName = readerName;
this.writerName = writerName;
}
public boolean isInherited() {
return inherited;
}
public boolean isVisible() {
return visible;
}
public String getReaderName() {
return readerName;
}
public String getWriterName() {
return writerName;
}
}
}

View File

@ -1,77 +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.enhance.internal.javassist;
import javassist.CannotCompileException;
import javassist.CtClass;
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import org.hibernate.engine.spi.CompositeOwner;
import org.hibernate.engine.spi.CompositeTracker;
import org.hibernate.engine.spi.ManagedComposite;
/**
* enhancer for composite (embeddable) entities
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class CompositeEnhancer extends PersistentAttributesEnhancer {
public CompositeEnhancer(JavassistEnhancementContext context) {
super( context );
}
public void enhance(CtClass managedCtClass) {
// add the ManagedComposite interface
managedCtClass.addInterface( loadCtClassFromClass( ManagedComposite.class ) );
addInterceptorHandling( managedCtClass );
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
addInLineDirtyHandling( managedCtClass );
}
super.enhance( managedCtClass );
}
/* --- */
private void addInLineDirtyHandling(CtClass managedCtClass) {
managedCtClass.addInterface( loadCtClassFromClass( CompositeTracker.class ) );
final CtClass compositeCtType = loadCtClassFromClass( CompositeOwnerTracker.class );
FieldWriter.addField( managedCtClass, compositeCtType, EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME );
createCompositeTrackerMethod( managedCtClass );
}
private void createCompositeTrackerMethod(CtClass managedCtClass) {
try {
MethodWriter.write( managedCtClass, "" +
"public void %1$s(String name, %3$s tracker) {%n" +
" if (%2$s == null) { %2$s = new %4$s(); }%n" +
" %2$s.add(name, tracker);%n" +
"}",
EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER,
EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME,
CompositeOwner.class.getName(),
CompositeOwnerTracker.class.getName() );
MethodWriter.write( managedCtClass, "" +
"public void %1$s(String name) {%n" +
" if (%2$s != null) { %2$s.removeOwner(name); }%n" +
"}",
EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER,
EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME );
}
catch (CannotCompileException cce) {
throw new RuntimeException( "createCompositeTrackerMethod failed", cce );
}
}
}

View File

@ -1,212 +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.enhance.internal.javassist;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import org.hibernate.HibernateException;
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.engine.spi.Managed;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
public class EnhancerImpl implements Enhancer {
private static final CoreMessageLogger log = CoreLogging.messageLogger( Enhancer.class );
protected final JavassistEnhancementContext enhancementContext;
private final ClassPool classPool;
/**
* Constructs the Enhancer, using the given context.
*
* @param enhancementContext Describes the context in which enhancement will occur so as to give access
* to contextual/environmental information.
*/
public EnhancerImpl(EnhancementContext enhancementContext) {
this.enhancementContext = new JavassistEnhancementContext( enhancementContext );
this.classPool = buildClassPool( this.enhancementContext );
}
EnhancerImpl(JavassistEnhancementContext enhancementContext) {
this.enhancementContext = enhancementContext;
this.classPool = buildClassPool( enhancementContext );
}
/**
* Performs the enhancement.
*
* @param className The name of the class whose bytecode is being enhanced.
* @param originalBytes The class's original (pre-enhancement) byte code
*
* @return The enhanced bytecode. Could be the same as the original bytecode if the original was
* already enhanced or we could not enhance it for some reason.
*
* @throws EnhancementException Indicates a problem performing the enhancement
*/
@Override
public synchronized byte[] enhance(String className, byte[] originalBytes) throws EnhancementException {
CtClass managedCtClass = null;
try {
managedCtClass = classPool.makeClassIfNew( new ByteArrayInputStream( originalBytes ) );
return enhance( managedCtClass ) ? getByteCode( managedCtClass ) : null;
}
catch (IOException e) {
log.unableToBuildEnhancementMetamodel( className );
return null;
}
finally {
if ( managedCtClass != null ) {
managedCtClass.detach();
}
}
}
private ClassPool buildClassPool(JavassistEnhancementContext enhancementContext) {
ClassPool classPool = new ClassPool( false ) {
@Override
public ClassLoader getClassLoader() {
return enhancementContext.getLoadingClassLoader();
}
};
ClassLoader loadingClassLoader = enhancementContext.getLoadingClassLoader();
if ( loadingClassLoader != null ) {
classPool.appendClassPath( new LoaderClassPath( loadingClassLoader ) );
}
return classPool;
}
protected CtClass loadCtClassFromClass(Class<?> aClass) {
String resourceName = aClass.getName().replace( '.', '/' ) + ".class";
InputStream resourceAsStream = aClass.getClassLoader().getResourceAsStream( resourceName );
if ( resourceAsStream == null ) {
throw new UncheckedIOException( new FileNotFoundException ( "Not found: " + resourceName ) );
}
try {
return classPool.makeClass( resourceAsStream );
}
catch (IOException e) {
throw new EnhancementException( "Could not prepare Javassist ClassPool", e );
}
finally {
try {
resourceAsStream.close();
}
catch (IOException ioe) {
log.debugf( "An error occurs closing InputStream for class [%s]", aClass.getName() );
}
}
}
private boolean enhance(CtClass managedCtClass) {
// can't effectively enhance interfaces
if ( managedCtClass.isInterface() ) {
log.debugf( "Skipping enhancement of [%s]: it's an interface!", managedCtClass.getName() );
return false;
}
// skip already enhanced classes
if ( alreadyEnhanced( managedCtClass ) ) {
log.debugf( "Skipping enhancement of [%s]: already enhanced", managedCtClass.getName() );
return false;
}
if ( enhancementContext.isEntityClass( managedCtClass ) ) {
log.debugf( "Enhancing [%s] as Entity", managedCtClass.getName() );
new EntityEnhancer( enhancementContext ).enhance( managedCtClass );
return true;
}
else if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() );
new CompositeEnhancer( enhancementContext ).enhance( managedCtClass );
return true;
}
else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() );
new MappedSuperclassEnhancer( enhancementContext ).enhance( managedCtClass );
return true;
}
else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() );
new PersistentAttributesEnhancer( enhancementContext ).extendedEnhancement( managedCtClass );
return true;
}
else {
log.debugf( "Skipping enhancement of [%s]: not entity or composite", managedCtClass.getName() );
return false;
}
}
// See HHH-10977 HHH-11284 HHH-11404 --- check for declaration of Managed interface on the class, not inherited
private boolean alreadyEnhanced(CtClass managedCtClass) {
try {
for ( CtClass declaredInterface : managedCtClass.getInterfaces() ) {
if ( PersistentAttributesHelper.isAssignable( declaredInterface, Managed.class.getName() ) ) {
return true;
}
}
return false;
}
catch ( NotFoundException e ) {
throw new HibernateException( "Unable to transform class: " + e.getMessage() , e );
}
}
private byte[] getByteCode(CtClass managedCtClass) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream( byteStream );
try {
managedCtClass.toBytecode( out );
return byteStream.toByteArray();
}
catch (Exception e) {
log.unableToTransformClass( e.getMessage() );
throw new HibernateException( "Unable to transform class: " + e.getMessage() , e );
}
finally {
try {
out.close();
}
catch (IOException ignored) {
}
}
}
protected void addInterceptorHandling(CtClass managedCtClass) {
// interceptor handling is only needed if class has lazy-loadable attributes
if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) {
return;
}
log.debugf( "Weaving in PersistentAttributeInterceptable implementation on [%s]", managedCtClass.getName() );
managedCtClass.addInterface( loadCtClassFromClass( PersistentAttributeInterceptable.class ) );
FieldWriter.addFieldWithGetterAndSetter(
managedCtClass,
loadCtClassFromClass( PersistentAttributeInterceptor.class ),
EnhancerConstants.INTERCEPTOR_FIELD_NAME,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
EnhancerConstants.INTERCEPTOR_SETTER_NAME
);
}
}

View File

@ -1,448 +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.enhance.internal.javassist;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtField;
import javassist.Modifier;
import javassist.NotFoundException;
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
import org.hibernate.bytecode.enhance.internal.tracker.NoopCollectionTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
import org.hibernate.bytecode.enhance.spi.CollectionTracker;
import org.hibernate.bytecode.enhance.spi.EnhancementException;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.ManagedEntity;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.SelfDirtinessTracker;
/**
* enhancer for regular entities
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class EntityEnhancer extends PersistentAttributesEnhancer {
public EntityEnhancer(JavassistEnhancementContext context) {
super( context );
}
// assuming the number of fields is not very high, SimpleFieldTracker implementation it's the fastest
private static final String DIRTY_TRACKER_IMPL = SimpleFieldTracker.class.getName();
private static final String COLLECTION_TRACKER_IMPL = SimpleCollectionTracker.class.getName();
public void enhance(CtClass managedCtClass) {
// add the ManagedEntity interface
managedCtClass.addInterface( loadCtClassFromClass( ManagedEntity.class ) );
addEntityInstanceHandling( managedCtClass );
addEntityEntryHandling( managedCtClass );
addLinkedPreviousHandling( managedCtClass );
addLinkedNextHandling( managedCtClass );
addInterceptorHandling( managedCtClass );
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
addInLineDirtyHandling( managedCtClass );
}
super.enhance( managedCtClass );
}
private void addEntityInstanceHandling(CtClass managedCtClass) {
try {
MethodWriter.write(
managedCtClass,
"public Object %s() { return this; }",
EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME
);
}
catch (CannotCompileException cce) {
throw new EnhancementException(
String.format(
Locale.ROOT,
"Could not enhance entity class [%s] to add EntityEntry getter",
managedCtClass.getName()
),
cce
);
}
}
private void addEntityEntryHandling(CtClass managedCtClass) {
FieldWriter.addFieldWithGetterAndSetter(
managedCtClass, loadCtClassFromClass( EntityEntry.class ),
EnhancerConstants.ENTITY_ENTRY_FIELD_NAME,
EnhancerConstants.ENTITY_ENTRY_GETTER_NAME,
EnhancerConstants.ENTITY_ENTRY_SETTER_NAME
);
}
private void addLinkedPreviousHandling(CtClass managedCtClass) {
FieldWriter.addFieldWithGetterAndSetter(
managedCtClass, loadCtClassFromClass( ManagedEntity.class ),
EnhancerConstants.PREVIOUS_FIELD_NAME,
EnhancerConstants.PREVIOUS_GETTER_NAME,
EnhancerConstants.PREVIOUS_SETTER_NAME
);
}
private void addLinkedNextHandling(CtClass managedCtClass) {
FieldWriter.addFieldWithGetterAndSetter(
managedCtClass, loadCtClassFromClass( ManagedEntity.class ),
EnhancerConstants.NEXT_FIELD_NAME,
EnhancerConstants.NEXT_GETTER_NAME,
EnhancerConstants.NEXT_SETTER_NAME
);
}
private void addInLineDirtyHandling(CtClass managedCtClass) {
managedCtClass.addInterface( loadCtClassFromClass( SelfDirtinessTracker.class ) );
FieldWriter.addField(
managedCtClass,
loadCtClassFromClass( DirtyTracker.class ),
EnhancerConstants.TRACKER_FIELD_NAME
);
if ( collectCollectionFields( managedCtClass ).isEmpty() ) {
createDirtyTrackerMethodsWithoutCollections( managedCtClass );
}
else {
FieldWriter.addField(
managedCtClass,
loadCtClassFromClass( CollectionTracker.class ),
EnhancerConstants.TRACKER_COLLECTION_NAME
);
createDirtyTrackerMethodsWithCollections( managedCtClass );
}
}
private void createDirtyTrackerMethodsWithoutCollections(CtClass managedCtClass) {
try {
MethodWriter.write(
managedCtClass,
"public void %1$s(String name) {%n" +
" if (%2$s == null) { %2$s = new %3$s(); }%n" +
" %2$s.add(name);%n" +
"}",
EnhancerConstants.TRACKER_CHANGER_NAME,
EnhancerConstants.TRACKER_FIELD_NAME,
DIRTY_TRACKER_IMPL
);
MethodWriter.write(
managedCtClass,
"public String[] %1$s() {%n" +
" return (%2$s == null) ? new String[0] : %2$s.get();%n" +
"}",
EnhancerConstants.TRACKER_GET_NAME,
EnhancerConstants.TRACKER_FIELD_NAME
);
MethodWriter.write(
managedCtClass,
"public boolean %1$s() {%n" +
" return (%2$s != null && !%2$s.isEmpty());%n" +
"}",
EnhancerConstants.TRACKER_HAS_CHANGED_NAME,
EnhancerConstants.TRACKER_FIELD_NAME
);
MethodWriter.write(
managedCtClass,
"public void %1$s() {%n" +
" if (%2$s != null) { %2$s.clear(); }%n" +
"}",
EnhancerConstants.TRACKER_CLEAR_NAME,
EnhancerConstants.TRACKER_FIELD_NAME
);
MethodWriter.write(
managedCtClass,
"public void %1$s(boolean f) {%n" +
" if (%2$s == null) %2$s = new %3$s();%n %2$s.suspend(f);%n" +
"}",
EnhancerConstants.TRACKER_SUSPEND_NAME,
EnhancerConstants.TRACKER_FIELD_NAME ,
DIRTY_TRACKER_IMPL
);
MethodWriter.write(
managedCtClass,
"public %s %s() { return %s.INSTANCE; }",
CollectionTracker.class.getName(),
EnhancerConstants.TRACKER_COLLECTION_GET_NAME,
NoopCollectionTracker.class.getName()
);
}
catch (CannotCompileException cce) {
throw new RuntimeException( "createDirtyTrackerMethodsWithoutCollections failed", cce );
}
}
private void createDirtyTrackerMethodsWithCollections(CtClass managedCtClass) {
try {
MethodWriter.write(
managedCtClass,
"public void %1$s(String name) {%n" +
" if (%2$s == null) { %2$s = new %3$s(); }%n" +
" %2$s.add(name);%n" +
"}",
EnhancerConstants.TRACKER_CHANGER_NAME,
EnhancerConstants.TRACKER_FIELD_NAME,
DIRTY_TRACKER_IMPL
);
createCollectionDirtyCheckMethod( managedCtClass );
createCollectionDirtyCheckGetFieldsMethod( managedCtClass );
createClearDirtyCollectionMethod( managedCtClass );
MethodWriter.write(
managedCtClass,
"public String[] %1$s() {%n" +
" if(%3$s == null) {%n" +
" return (%2$s == null) ? new String[0] : %2$s.get();%n" +
" } else {%n" +
" if (%2$s == null) %2$s = new %5$s();%n" +
" %4$s(%2$s);%n" +
" return %2$s.get();%n" +
" }%n" +
"}",
EnhancerConstants.TRACKER_GET_NAME,
EnhancerConstants.TRACKER_FIELD_NAME,
EnhancerConstants.TRACKER_COLLECTION_NAME,
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
DIRTY_TRACKER_IMPL
);
MethodWriter.write(
managedCtClass,
"public boolean %1$s() {%n" +
" return (%2$s != null && !%2$s.isEmpty()) || %3$s();%n" +
"}",
EnhancerConstants.TRACKER_HAS_CHANGED_NAME,
EnhancerConstants.TRACKER_FIELD_NAME,
EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME
);
MethodWriter.write(
managedCtClass,
"public void %1$s() {%n" +
" if (%2$s != null) { %2$s.clear(); }%n" +
" %3$s();%n" +
"}",
EnhancerConstants.TRACKER_CLEAR_NAME,
EnhancerConstants.TRACKER_FIELD_NAME,
EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME
);
MethodWriter.write(
managedCtClass,
"public void %1$s(boolean f) {%n" +
" if (%2$s == null) %2$s = new %3$s();%n %2$s.suspend(f);%n" +
"}",
EnhancerConstants.TRACKER_SUSPEND_NAME,
EnhancerConstants.TRACKER_FIELD_NAME ,
DIRTY_TRACKER_IMPL
);
MethodWriter.write(
managedCtClass,
"public %s %s() { return %s; }",
CollectionTracker.class.getName(),
EnhancerConstants.TRACKER_COLLECTION_GET_NAME,
EnhancerConstants.TRACKER_COLLECTION_NAME
);
}
catch (CannotCompileException cce) {
throw new RuntimeException( "createDirtyTrackerMethodsWithCollections failed", cce );
}
}
private List<CtField> collectCollectionFields(CtClass managedCtClass) {
List<CtField> collectionList = new ArrayList<>();
for ( CtField ctField : managedCtClass.getDeclaredFields() ) {
// skip static fields and skip fields added by enhancement
if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) {
continue;
}
if ( enhancementContext.isPersistentField( ctField ) && enhancementContext.isMappedCollection( ctField ) ) {
if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) ||
PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) {
collectionList.add( ctField );
}
}
}
// HHH-10646 Add fields inherited from @MappedSuperclass
// HHH-10981 There is no need to do it for @MappedSuperclass
if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
collectionList.addAll( collectInheritCollectionFields( managedCtClass ) );
}
return collectionList;
}
private Collection<CtField> collectInheritCollectionFields(CtClass managedCtClass) {
if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) {
return Collections.emptyList();
}
try {
CtClass managedCtSuperclass = managedCtClass.getSuperclass();
if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) {
return collectInheritCollectionFields( managedCtSuperclass );
}
List<CtField> collectionList = new ArrayList<CtField>();
for ( CtField ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( !Modifier.isStatic( ctField.getModifiers() ) ) {
if ( enhancementContext.isPersistentField( ctField ) && enhancementContext.isMappedCollection( ctField ) ) {
if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) ||
PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) {
collectionList.add( ctField );
}
}
}
}
collectionList.addAll( collectInheritCollectionFields( managedCtSuperclass ) );
return collectionList;
}
catch ( NotFoundException nfe ) {
return Collections.emptyList();
}
}
private void createCollectionDirtyCheckMethod(CtClass managedCtClass) {
try {
final StringBuilder body = new StringBuilder();
body.append(
String.format(
"private boolean %1$s() {%n" +
" if (%2$s == null) { return false; }%n%n",
EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME,
EnhancerConstants.TRACKER_COLLECTION_NAME
)
);
for ( CtField ctField : collectCollectionFields( managedCtClass ) ) {
body.append(
String.format(
" // collection field [%1$s]%n" +
" if (%1$s == null && %2$s.getSize(\"%1$s\") != -1) { return true; }%n" +
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { return true; }%n%n",
ctField.getName(),
EnhancerConstants.TRACKER_COLLECTION_NAME
)
);
}
body.append( " return false;%n}" );
MethodWriter.write( managedCtClass, body.toString() );
}
catch (CannotCompileException cce) {
throw new RuntimeException( "createCollectionDirtyCheckMethod failed", cce );
}
}
private void createCollectionDirtyCheckGetFieldsMethod(CtClass managedCtClass) {
try {
final StringBuilder body = new StringBuilder();
body.append(
String.format(
"private void %1$s(%3$s tracker) {%n" +
" if (%2$s == null) { return; }%n%n",
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
EnhancerConstants.TRACKER_COLLECTION_NAME,
DirtyTracker.class.getName()
)
);
for ( CtField ctField : collectCollectionFields( managedCtClass ) ) {
body.append(
String.format(
" // Collection field [%1$s]%n" +
" if (%1$s == null && %2$s.getSize(\"%1$s\") != -1) { tracker.add(\"%1$s\"); }%n" +
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { tracker.add(\"%1$s\"); }%n%n",
ctField.getName(),
EnhancerConstants.TRACKER_COLLECTION_NAME
)
);
}
body.append( "}" );
MethodWriter.write( managedCtClass, body.toString() );
}
catch (CannotCompileException cce) {
throw new RuntimeException( "createCollectionDirtyCheckGetFieldsMethod failed", cce );
}
}
private void createClearDirtyCollectionMethod(CtClass managedCtClass) throws CannotCompileException {
try {
final StringBuilder body = new StringBuilder();
body.append(
String.format(
"private void %1$s() {%n" +
" if (%2$s == null) { %2$s = new %3$s(); }%n" +
" %4$s lazyInterceptor = null;%n",
EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME,
EnhancerConstants.TRACKER_COLLECTION_NAME,
COLLECTION_TRACKER_IMPL,
LazyAttributeLoadingInterceptor.class.getName()
)
);
if ( PersistentAttributesHelper.isAssignable( managedCtClass, PersistentAttributeInterceptable.class.getName() ) ) {
body.append(
String.format(
" if(%1$s != null && %1$s instanceof %2$s) lazyInterceptor = (%2$s) %1$s;%n%n",
EnhancerConstants.INTERCEPTOR_FIELD_NAME,
LazyAttributeLoadingInterceptor.class.getName()
)
);
}
for ( CtField ctField : collectCollectionFields( managedCtClass ) ) {
body.append(
String.format(
" // collection field [%1$s]%n" +
" if (lazyInterceptor == null || lazyInterceptor.isAttributeLoaded(\"%1$s\")) {%n" +
" if (%1$s == null) { %2$s.add(\"%1$s\", -1); }%n" +
" else { %2$s.add(\"%1$s\", %1$s.size()); }%n" +
" }%n%n",
ctField.getName(),
EnhancerConstants.TRACKER_COLLECTION_NAME
)
);
}
body.append( "}" );
MethodWriter.write( managedCtClass, body.toString() );
}
catch (CannotCompileException cce) {
throw cce;
}
}
}

View File

@ -1,83 +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.enhance.internal.javassist;
import javax.persistence.Transient;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtField;
import javassist.Modifier;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.FieldInfo;
import javassist.bytecode.annotation.Annotation;
import org.hibernate.bytecode.enhance.spi.EnhancementException;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
/**
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class FieldWriter {
private static final CoreMessageLogger log = CoreLogging.messageLogger( FieldWriter.class );
private FieldWriter() { }
/* --- */
/**
* Add enhancement field
*/
public static void addField(CtClass target, CtClass type, String field) {
addPrivateTransient( target, type, field );
}
/**
* Add enhancement field with getter and setter
*/
public static void addFieldWithGetterAndSetter(CtClass target, CtClass type, String field, String getter, String setter) {
addPrivateTransient( target, type, field );
MethodWriter.addGetter( target, field, getter );
MethodWriter.addSetter( target, field, setter );
}
/* --- */
private static void addPrivateTransient(CtClass target, CtClass type, String name) {
addWithModifiers( target, type, name, Modifier.PRIVATE | Modifier.TRANSIENT, Transient.class );
log.debugf( "Wrote field into [%s]: @Transient private transient %s %s;", target.getName(), type.getName(), name );
}
private static void addWithModifiers(CtClass target, CtClass type, String name, int modifiers, Class<?> ... annotations ) {
try {
final CtField f = new CtField( type, name, target );
f.setModifiers( f.getModifiers() | modifiers );
addAnnotations( f.getFieldInfo(), annotations );
target.addField( f );
}
catch (CannotCompileException cce) {
final String msg = String.format( "Could not enhance class [%s] to add field [%s]", target.getName(), name );
throw new EnhancementException( msg, cce );
}
}
/* --- */
private static void addAnnotations(FieldInfo fieldInfo, Class<?>[] annotations) {
AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) fieldInfo.getAttribute( AnnotationsAttribute.visibleTag );
if ( annotationsAttribute == null ) {
annotationsAttribute = new AnnotationsAttribute( fieldInfo.getConstPool(), AnnotationsAttribute.visibleTag );
fieldInfo.addAttribute( annotationsAttribute );
}
for (Class<?> annotation : annotations) {
annotationsAttribute.addAnnotation( new Annotation( annotation.getName(), fieldInfo.getConstPool() ) );
}
}
}

View File

@ -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.bytecode.enhance.internal.javassist;
import javassist.CtClass;
import javassist.CtField;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.UnloadedField;
public class JavassistEnhancementContext {
private final EnhancementContext enhancementContext;
public JavassistEnhancementContext(EnhancementContext enhancementContext) {
this.enhancementContext = enhancementContext;
}
public ClassLoader getLoadingClassLoader() {
return enhancementContext.getLoadingClassLoader();
}
public boolean isEntityClass(CtClass classDescriptor) {
return enhancementContext.isEntityClass( new UnloadedCtClass( classDescriptor ) );
}
public boolean isCompositeClass(CtClass classDescriptor) {
return enhancementContext.isCompositeClass( new UnloadedCtClass( classDescriptor ) );
}
public boolean isMappedSuperclassClass(CtClass classDescriptor) {
return enhancementContext.isMappedSuperclassClass( new UnloadedCtClass( classDescriptor ) );
}
public boolean doBiDirectionalAssociationManagement(CtField field) {
return enhancementContext.doBiDirectionalAssociationManagement( new UnloadedCtField( field ) );
}
public boolean doDirtyCheckingInline(CtClass classDescriptor) {
return enhancementContext.doDirtyCheckingInline( new UnloadedCtClass( classDescriptor ) );
}
public boolean doExtendedEnhancement(CtClass classDescriptor) {
return enhancementContext.doExtendedEnhancement( new UnloadedCtClass( classDescriptor ) );
}
public boolean hasLazyLoadableAttributes(CtClass classDescriptor) {
return enhancementContext.hasLazyLoadableAttributes( new UnloadedCtClass( classDescriptor ) );
}
public boolean isPersistentField(CtField ctField) {
return enhancementContext.isPersistentField( new UnloadedCtField( ctField ) );
}
public CtField[] order(CtField[] persistentFields) {
UnloadedField[] unloadedFields = new UnloadedField[persistentFields.length];
for ( int i = 0; i < unloadedFields.length; i++ ) {
unloadedFields[i] = new UnloadedCtField( persistentFields[i] );
}
UnloadedField[] ordered = enhancementContext.order( unloadedFields );
CtField[] orderedFields = new CtField[persistentFields.length];
for ( int i = 0; i < orderedFields.length; i++ ) {
orderedFields[i] = ( (UnloadedCtField) ordered[i] ).ctField;
}
return orderedFields;
}
public boolean isLazyLoadable(CtField field) {
return enhancementContext.isLazyLoadable( new UnloadedCtField( field ) );
}
public boolean isMappedCollection(CtField field) {
return enhancementContext.isMappedCollection( new UnloadedCtField( field ) );
}
}

View File

@ -1,61 +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.enhance.internal.javassist;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import org.hibernate.engine.spi.ManagedMappedSuperclass;
/**
* enhancer for mapped superclass
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class MappedSuperclassEnhancer extends PersistentAttributesEnhancer {
public MappedSuperclassEnhancer(JavassistEnhancementContext context) {
super( context );
}
public void enhance(CtClass managedCtClass) {
// Add the Managed interface
managedCtClass.addInterface( loadCtClassFromClass( ManagedMappedSuperclass.class ) );
super.enhance( managedCtClass );
}
// Generate 'template' methods for each attribute. This will be overridden by the actual entities
@Override
protected CtMethod generateFieldReader(
CtClass managedCtClass,
CtField persistentField,
AttributeTypeDescriptor typeDescriptor) {
String fieldName = persistentField.getName();
String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName;
return MethodWriter.addGetter( managedCtClass, fieldName, readerName );
}
@Override
protected CtMethod generateFieldWriter(
CtClass managedCtClass,
CtField persistentField,
AttributeTypeDescriptor typeDescriptor) {
String fieldName = persistentField.getName();
String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName;
return MethodWriter.addSetter( managedCtClass, fieldName, writerName );
}
}

View File

@ -1,109 +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.enhance.internal.javassist;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
import javassist.bytecode.ConstPool;
import org.hibernate.bytecode.enhance.spi.EnhancementException;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
/**
* utility class to compile methods and add the to class files
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class MethodWriter {
private static final CoreMessageLogger log = CoreLogging.messageLogger( MethodWriter.class );
private MethodWriter() { }
/* --- */
/**
* convenience method that builds a method from a format string. {@see String.format} for more details
*
* @throws CannotCompileException
*/
public static CtMethod write(CtClass target, String format, Object ... args) throws CannotCompileException {
String body = String.format( format, args );
// System.out.printf( "writing method into [%s]:%n%s%n", target.getName(), body );
log.debugf( "writing method into [%s]:%n%s", target.getName(), body );
CtMethod method = CtNewMethod.make( body, target );
target.addMethod( method );
return method;
}
/* --- */
public static CtMethod addGetter(CtClass target, String field, String name) {
CtField actualField = null;
try {
actualField = target.getField( field );
log.debugf( "Writing getter method [%s] into [%s] for field [%s]", name, target.getName(), field );
CtMethod method = CtNewMethod.getter( name, target.getField( field ) );
target.addMethod( method );
return method;
}
catch (CannotCompileException cce) {
try {
// Fall back to create a getter from delegation.
CtMethod method = CtNewMethod.delegator( CtNewMethod.getter( name, actualField ), target );
target.addMethod( method );
return method;
}
catch (CannotCompileException ignored) {
String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field );
throw new EnhancementException( msg, cce );
}
}
catch (NotFoundException nfe) {
String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field );
throw new EnhancementException( msg, nfe );
}
}
public static CtMethod addSetter(CtClass target, String field, String name) {
CtField actualField = null;
try {
actualField = target.getField( field );
log.debugf( "Writing setter method [%s] into [%s] for field [%s]", name, target.getName(), field );
CtMethod method = CtNewMethod.setter( name, actualField );
target.addMethod( method );
return method;
}
catch (CannotCompileException cce) {
try {
// Fall back to create a getter from delegation.
CtMethod method = CtNewMethod.delegator( CtNewMethod.setter( name, actualField ), target );
target.addMethod( method );
return method;
}
catch (CannotCompileException ignored) {
String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field );
throw new EnhancementException( msg, cce );
}
}
catch (NotFoundException nfe) {
String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field );
throw new EnhancementException( msg, nfe );
}
}
/* --- */
public static int addMethod(ConstPool cPool, CtMethod method) {
return cPool.addMethodrefInfo( cPool.getThisClassInfo(), method.getName(), method.getSignature() );
}
}

View File

@ -1,745 +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.enhance.internal.javassist;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.Embedded;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.Opcode;
import javassist.bytecode.stackmap.MapMaker;
import org.hibernate.Hibernate;
import org.hibernate.bytecode.enhance.spi.EnhancementException;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import org.hibernate.engine.spi.CompositeOwner;
import org.hibernate.engine.spi.CompositeTracker;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
/**
* enhancer for persistent attributes of any type of entity
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
*/
public class PersistentAttributesEnhancer extends EnhancerImpl {
private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributesEnhancer.class );
public PersistentAttributesEnhancer(JavassistEnhancementContext context) {
super( context );
}
public void enhance(CtClass managedCtClass) {
final IdentityHashMap<String, PersistentAttributeAccessMethods> attrDescriptorMap = new IdentityHashMap<String, PersistentAttributeAccessMethods>();
for ( CtField persistentField : collectPersistentFields( managedCtClass ) ) {
attrDescriptorMap.put(
persistentField.getName(), enhancePersistentAttribute(
managedCtClass,
persistentField
)
);
}
// find all references to the transformed fields and replace with calls to the added reader/writer methods
enhanceAttributesAccess( managedCtClass, attrDescriptorMap );
// same thing for direct access to fields of other entities
if ( this.enhancementContext.doExtendedEnhancement( managedCtClass ) ) {
extendedEnhancement( managedCtClass );
}
}
private CtField[] collectPersistentFields(CtClass managedCtClass) {
List<CtField> persistentFieldList = new ArrayList<CtField>();
for ( CtField ctField : managedCtClass.getDeclaredFields() ) {
// skip static fields and skip fields added by enhancement and outer reference in inner classes
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
continue;
}
if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) {
persistentFieldList.add( ctField );
}
}
// HHH-10646 Add fields inherited from @MappedSuperclass
// HHH-10981 There is no need to do it for @MappedSuperclass
if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
persistentFieldList.addAll( collectInheritPersistentFields( managedCtClass ) );
}
CtField[] orderedFields = enhancementContext.order( persistentFieldList.toArray( new CtField[0] ) );
log.debugf( "Persistent fields for entity %s: %s", managedCtClass.getName(), Arrays.toString( orderedFields ) );
return orderedFields;
}
private Collection<CtField> collectInheritPersistentFields(CtClass managedCtClass) {
if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) {
return Collections.emptyList();
}
try {
CtClass managedCtSuperclass = managedCtClass.getSuperclass();
if ( enhancementContext.isEntityClass( managedCtSuperclass ) ) {
return Collections.emptyList();
}
else if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) {
return collectInheritPersistentFields( managedCtSuperclass );
}
log.debugf( "Found @MappedSuperclass %s to collectPersistenceFields", managedCtSuperclass.getName() );
List<CtField> persistentFieldList = new ArrayList<CtField>();
for ( CtField ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) {
continue;
}
if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) {
persistentFieldList.add( ctField );
}
}
persistentFieldList.addAll( collectInheritPersistentFields( managedCtSuperclass ) );
return persistentFieldList;
}
catch ( NotFoundException nfe ) {
log.warnf( "Could not find the superclass of %s", managedCtClass );
return Collections.emptyList();
}
}
private PersistentAttributeAccessMethods enhancePersistentAttribute(CtClass managedCtClass, CtField persistentField) {
try {
AttributeTypeDescriptor typeDescriptor = AttributeTypeDescriptor.resolve( managedCtClass, persistentField );
return new PersistentAttributeAccessMethods(
generateFieldReader( managedCtClass, persistentField, typeDescriptor ),
generateFieldWriter( managedCtClass, persistentField, typeDescriptor )
);
}
catch (Exception e) {
final String msg = String.format(
"Unable to enhance persistent attribute [%s:%s]",
managedCtClass.getName(),
persistentField.getName()
);
throw new EnhancementException( msg, e );
}
}
protected CtMethod generateFieldReader(
CtClass managedCtClass,
CtField persistentField,
AttributeTypeDescriptor typeDescriptor) {
String fieldName = persistentField.getName();
String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName;
String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName;
CtMethod tmpSuperReader = null;
CtMethod tmpSuperWriter = null;
CtMethod reader = null;
try {
boolean declared = persistentField.getDeclaringClass().equals( managedCtClass );
String declaredReadFragment = "this." + fieldName;
String superReadFragment = "super." + readerName + "()";
if ( !declared ) {
// create a temporary getter on the supper entity to be able to compile our code
try {
persistentField.getDeclaringClass().getDeclaredMethod( readerName );
persistentField.getDeclaringClass().getDeclaredMethod( writerName );
}
catch ( NotFoundException nfe ) {
tmpSuperReader = MethodWriter.addGetter( persistentField.getDeclaringClass(), persistentField.getName(), readerName );
tmpSuperWriter = MethodWriter.addSetter( persistentField.getDeclaringClass(), persistentField.getName(), writerName );
}
}
// read attempts only have to deal lazy-loading support, not dirty checking;
// so if the field is not enabled as lazy-loadable return a plain simple getter as the reader
if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( persistentField ) ) {
reader = MethodWriter.write(
managedCtClass, "public %s %s() { return %s;%n}",
persistentField.getType().getName(),
readerName,
declared ? declaredReadFragment : superReadFragment
);
}
else {
reader = MethodWriter.write(
managedCtClass, "public %s %s() {%n%s%n return %s;%n}",
persistentField.getType().getName(),
readerName,
typeDescriptor.buildReadInterceptionBodyFragment( fieldName ),
declared ? declaredReadFragment : superReadFragment
);
}
if ( tmpSuperReader != null ) {
persistentField.getDeclaringClass().removeMethod( tmpSuperReader );
}
if ( tmpSuperWriter != null ) {
persistentField.getDeclaringClass().removeMethod( tmpSuperWriter );
}
return reader;
}
catch (CannotCompileException cce) {
final String msg = String.format(
"Could not enhance entity class [%s] to add field reader method [%s]",
managedCtClass.getName(),
readerName
);
throw new EnhancementException( msg, cce );
}
catch (NotFoundException nfe) {
final String msg = String.format(
"Could not enhance entity class [%s] to add field reader method [%s]",
managedCtClass.getName(),
readerName
);
throw new EnhancementException( msg, nfe );
}
}
protected CtMethod generateFieldWriter(
CtClass managedCtClass,
CtField persistentField,
AttributeTypeDescriptor typeDescriptor) {
String fieldName = persistentField.getName();
String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName;
String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName;
CtMethod tmpSuperReader = null;
CtMethod tmpSuperWriter = null;
CtMethod writer;
try {
boolean declared = persistentField.getDeclaringClass().equals( managedCtClass );
String declaredWriteFragment = "this." + fieldName + "=" + fieldName + ";";
String superWriteFragment = "super." + writerName + "(" + fieldName + ");";
if ( !declared ) {
// create a temporary setter on the supper entity to be able to compile our code
try {
persistentField.getDeclaringClass().getDeclaredMethod( readerName );
persistentField.getDeclaringClass().getDeclaredMethod( writerName );
}
catch ( NotFoundException nfe ) {
tmpSuperReader = MethodWriter.addGetter( persistentField.getDeclaringClass(), persistentField.getName(), readerName );
tmpSuperWriter = MethodWriter.addSetter( persistentField.getDeclaringClass(), persistentField.getName(), writerName );
}
}
if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( persistentField ) ) {
writer = MethodWriter.write(
managedCtClass,
"public void %s(%s %s) {%n %s%n}",
writerName,
persistentField.getType().getName(),
fieldName,
declared ? declaredWriteFragment : superWriteFragment
);
}
else {
writer = MethodWriter.write(
managedCtClass,
"public void %s(%s %s) {%n%s%n}",
writerName,
persistentField.getType().getName(),
fieldName,
typeDescriptor.buildWriteInterceptionBodyFragment( fieldName )
);
}
if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) {
if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
writer.insertBefore(
String.format(
" if (%1$s != null) { %1$s.callOwner(\"\"); }%n",
EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME
)
);
}
else {
writer.insertBefore( typeDescriptor.buildInLineDirtyCheckingBodyFragment( enhancementContext, persistentField ) );
}
handleCompositeField( managedCtClass, persistentField, writer );
}
if ( enhancementContext.doBiDirectionalAssociationManagement( persistentField ) ) {
handleBiDirectionalAssociation( managedCtClass, persistentField, writer );
}
if ( tmpSuperReader != null ) {
persistentField.getDeclaringClass().removeMethod( tmpSuperReader );
}
if ( tmpSuperWriter != null ) {
persistentField.getDeclaringClass().removeMethod( tmpSuperWriter );
}
return writer;
}
catch (CannotCompileException cce) {
final String msg = String.format(
"Could not enhance entity class [%s] to add field writer method [%s]",
managedCtClass.getName(),
writerName
);
throw new EnhancementException( msg, cce );
}
catch (NotFoundException nfe) {
final String msg = String.format(
"Could not enhance entity class [%s] to add field writer method [%s]",
managedCtClass.getName(),
writerName
);
throw new EnhancementException( msg, nfe );
}
}
private void handleBiDirectionalAssociation(CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter)
throws NotFoundException, CannotCompileException {
if ( !PersistentAttributesHelper.isPossibleBiDirectionalAssociation( persistentField ) ) {
return;
}
final CtClass targetEntity = PersistentAttributesHelper.getTargetEntityClass( managedCtClass, persistentField );
if ( targetEntity == null ) {
log.infof(
"Bi-directional association not managed for field [%s#%s]: Could not find target type",
managedCtClass.getName(),
persistentField.getName()
);
return;
}
final String mappedBy = PersistentAttributesHelper.getMappedBy( persistentField, targetEntity, enhancementContext );
if ( mappedBy == null || mappedBy.isEmpty() ) {
log.infof(
"Bi-directional association not managed for field [%s#%s]: Could not find target field in [%s]",
managedCtClass.getName(),
persistentField.getName(),
targetEntity.getName()
);
return;
}
// create a temporary getter and setter on the target entity to be able to compile our code
final String mappedByGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + mappedBy;
final String mappedBySetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + mappedBy;
CtMethod getter;
CtMethod setter;
boolean tmpTargetMethods = false;
try {
getter = targetEntity.getDeclaredMethod( mappedByGetterName );
setter = targetEntity.getDeclaredMethod( mappedByGetterName );
}
catch ( NotFoundException nfe ) {
getter = MethodWriter.addGetter( targetEntity, mappedBy, mappedByGetterName );
setter = MethodWriter.addSetter( targetEntity, mappedBy, mappedBySetterName );
tmpTargetMethods = true;
}
// code fragments to check loaded state. We don't want to trigger lazy loading in association management code
String currentAssociationLoaded = String.format(
"%s.isPropertyInitialized(this.%s, \"%s\")",
Hibernate.class.getName(),
persistentField.getName(),
mappedBy
);
String targetElementLoaded = String.format(
"%s.isPropertyInitialized(target, \"%s\")",
Hibernate.class.getName(),
mappedBy
);
String newAssociationLoaded = String.format(
"%s.isPropertyInitialized($1, \"%s\")",
Hibernate.class.getName(),
mappedBy
);
if ( PersistentAttributesHelper.hasAnnotation( persistentField, OneToOne.class ) ) {
// only unset when $1 != null to avoid recursion
fieldWriter.insertBefore(
String.format(
" if (this.%1$s != null && %2$s && $1 != null) { this.%1$s.%3$s(null); }%n",
persistentField.getName(),
currentAssociationLoaded,
mappedBySetterName
)
);
fieldWriter.insertAfter(
String.format(
" if ($1 != null && %s && $1.%s() != this) { $1.%s(this); }%n",
newAssociationLoaded,
mappedByGetterName,
mappedBySetterName
)
);
}
if ( PersistentAttributesHelper.hasAnnotation( persistentField, OneToMany.class ) ) {
boolean isMap = PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() );
String toArrayMethod = isMap ? "values().toArray()" : "toArray()";
// only remove elements not in the new collection or else we would loose those elements
// don't use iterator to avoid ConcurrentModificationException
fieldWriter.insertBefore(
String.format(
" if (this.%3$s != null && %1$s) {%n" +
" Object[] array = this.%3$s.%2$s;%n" +
" for (int i = 0; i < array.length; i++) {%n" +
" %4$s target = (%4$s) array[i];%n" +
" if ($1 == null || !$1.contains(target)) { target.%5$s(null); }%n" +
" }%n" +
" }%n",
currentAssociationLoaded,
toArrayMethod,
persistentField.getName(),
targetEntity.getName(),
mappedBySetterName
)
);
fieldWriter.insertAfter(
String.format(
" if ($1 != null && %1$s) {%n" +
" Object[] array = $1.%2$s;%n" +
" for (int i = 0; i < array.length; i++) {%n" +
" %4$s target = (%4$s) array[i];%n" +
" if (%3$s && target.%5$s() != this) { target.%6$s(this); }%n" +
" }%n" +
" }%n",
newAssociationLoaded,
toArrayMethod,
targetElementLoaded,
targetEntity.getName(),
mappedByGetterName,
mappedBySetterName
)
);
}
if ( PersistentAttributesHelper.hasAnnotation( persistentField, ManyToOne.class ) ) {
fieldWriter.insertBefore(
String.format(
" if (this.%2$s != null && %1$s && this.%2$s.%3$s() != null) { this.%2$s.%3$s().remove(this); }%n",
currentAssociationLoaded,
persistentField.getName(),
mappedByGetterName
)
);
// check .contains(this) to avoid double inserts (but preventing duplicates)
fieldWriter.insertAfter(
String.format(
" if ($1 != null && %s) {%n" +
" java.util.Collection c = $1.%s();%n" +
" if (c != null && !c.contains(this)) { c.add(this); }%n" +
" }%n",
newAssociationLoaded,
mappedByGetterName
)
);
}
if ( PersistentAttributesHelper.hasAnnotation( persistentField, ManyToMany.class ) ) {
if ( PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() ) ||
PersistentAttributesHelper.isAssignable( targetEntity.getField( mappedBy ).getType(), Map.class.getName() ) ) {
log.infof(
"Bi-directional association not managed for field [%s#%s]: @ManyToMany in java.util.Map attribute not supported ",
managedCtClass.getName(),
persistentField.getName()
);
return;
}
fieldWriter.insertBefore(
String.format(
" if (this.%2$s != null && %1$s) {%n" +
" Object[] array = this.%2$s.toArray();%n" +
" for (int i = 0; i < array.length; i++) {%n" +
" %3$s target = (%3$s) array[i];%n" +
" if ($1 == null || !$1.contains(target)) { target.%4$s().remove(this); }%n" +
" }%n" +
" }%n",
currentAssociationLoaded,
persistentField.getName(),
targetEntity.getName(),
mappedByGetterName
)
);
fieldWriter.insertAfter(
String.format(
" if ($1 != null && %s) {%n" +
" Object[] array = $1.toArray();%n" +
" for (int i = 0; i < array.length; i++) {%n" +
" %s target = (%s) array[i];%n" +
" if (%s) {%n" +
" java.util.Collection c = target.%s();%n" +
" if (c != this && c != null) { c.add(this); }%n" +
" }%n" +
" }%n" +
" }%n",
newAssociationLoaded,
targetEntity.getName(),
targetEntity.getName(),
targetElementLoaded,
mappedByGetterName
)
);
}
// implementation note: association management @OneToMany and @ManyToMay works for add() operations but for remove() a snapshot of the collection is needed so we know what associations to break.
// another approach that could force that behavior would be to return Collections.unmodifiableCollection() ...
if ( tmpTargetMethods ) {
targetEntity.removeMethod( getter );
targetEntity.removeMethod( setter );
}
}
private void handleCompositeField(CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter)
throws NotFoundException, CannotCompileException {
if ( !enhancementContext.isCompositeClass( persistentField.getType() ) ||
!PersistentAttributesHelper.hasAnnotation( persistentField, Embedded.class ) ) {
return;
}
// make sure to add the CompositeOwner interface
addCompositeOwnerInterface( managedCtClass );
String readFragment = persistentField.visibleFrom( managedCtClass ) ? persistentField.getName() : "super." + EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName() + "()";
// cleanup previous owner
fieldWriter.insertBefore(
String.format(
"if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%4$s\"); }%n",
readFragment,
CompositeTracker.class.getName(),
EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER,
persistentField.getName()
)
);
// trigger track changes
fieldWriter.insertAfter(
String.format(
"if (%1$s != null) { ((%2$s) %1$s).%4$s(\"%6$s\", (%3$s) this); }%n" +
"%5$s(\"%6$s\");",
readFragment,
CompositeTracker.class.getName(),
CompositeOwner.class.getName(),
EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER,
EnhancerConstants.TRACKER_CHANGER_NAME,
persistentField.getName()
)
);
}
private void addCompositeOwnerInterface(CtClass managedCtClass) throws NotFoundException, CannotCompileException {
CtClass compositeOwnerCtClass = managedCtClass.getClassPool().get( CompositeOwner.class.getName() );
// HHH-10540 only add the interface once
for ( CtClass i : managedCtClass.getInterfaces() ) {
if ( i.subclassOf( compositeOwnerCtClass ) ) {
return;
}
}
managedCtClass.addInterface( compositeOwnerCtClass );
if ( enhancementContext.isCompositeClass( managedCtClass ) ) {
// if a composite has an embedded field we need to implement the TRACKER_CHANGER_NAME method as well
MethodWriter.write(
managedCtClass,
"public void %1$s(String name) {%n" +
" if (%2$s != null) { %2$s.callOwner(\".\" + name); }%n}",
EnhancerConstants.TRACKER_CHANGER_NAME,
EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME
);
}
}
protected void enhanceAttributesAccess(
CtClass managedCtClass,
IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
final ConstPool constPool = managedCtClass.getClassFile().getConstPool();
final ClassPool classPool = managedCtClass.getClassPool();
for ( Object oMethod : managedCtClass.getClassFile().getMethods() ) {
final MethodInfo methodInfo = (MethodInfo) oMethod;
final String methodName = methodInfo.getName();
// skip methods added by enhancement and abstract methods (methods without any code)
if ( methodName.startsWith( "$$_hibernate_" ) || methodInfo.getCodeAttribute() == null ) {
continue;
}
try {
final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
while ( itr.hasNext() ) {
final int index = itr.next();
final int op = itr.byteAt( index );
if ( op != Opcode.PUTFIELD && op != Opcode.GETFIELD ) {
continue;
}
// only transform access to fields of the entity being enhanced
if ( !managedCtClass.getName().equals( constPool.getFieldrefClassName( itr.u16bitAt( index + 1 ) ) ) ) {
continue;
}
final String fieldName = constPool.getFieldrefName( itr.u16bitAt( index + 1 ) );
final PersistentAttributeAccessMethods attributeMethods = attributeDescriptorMap.get( fieldName );
// its not a field we have enhanced for interception, so skip it
if ( attributeMethods == null ) {
continue;
}
//System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName, methodName );
log.debugf( "Transforming access to field [%s] from method [%s]", fieldName, methodName );
if ( op == Opcode.GETFIELD ) {
final int methodIndex = MethodWriter.addMethod( constPool, attributeMethods.getReader() );
itr.writeByte( Opcode.INVOKEVIRTUAL, index );
itr.write16bit( methodIndex, index + 1 );
}
else {
final int methodIndex = MethodWriter.addMethod( constPool, attributeMethods.getWriter() );
itr.writeByte( Opcode.INVOKEVIRTUAL, index );
itr.write16bit( methodIndex, index + 1 );
}
}
methodInfo.getCodeAttribute().setAttribute( MapMaker.make( classPool, methodInfo ) );
}
catch (BadBytecode bb) {
final String msg = String.format(
"Unable to perform field access transformation in method [%s]",
methodName
);
throw new EnhancementException( msg, bb );
}
}
}
private static class PersistentAttributeAccessMethods {
private final CtMethod reader;
private final CtMethod writer;
private PersistentAttributeAccessMethods(CtMethod reader, CtMethod writer) {
this.reader = reader;
this.writer = writer;
}
private CtMethod getReader() {
return reader;
}
private CtMethod getWriter() {
return writer;
}
}
// --- //
/**
* Replace access to fields of entities (for example, entity.field) with a call to the enhanced getter / setter
* (in this example, entity.$$_hibernate_read_field()). It's assumed that the target entity is enhanced as well.
*
* @param aCtClass Class to enhance (not an entity class).
*/
public void extendedEnhancement(CtClass aCtClass) {
final ConstPool constPool = aCtClass.getClassFile().getConstPool();
final ClassPool classPool = aCtClass.getClassPool();
for ( Object oMethod : aCtClass.getClassFile().getMethods() ) {
final MethodInfo methodInfo = (MethodInfo) oMethod;
final String methodName = methodInfo.getName();
// skip methods added by enhancement and abstract methods (methods without any code)
if ( methodName.startsWith( "$$_hibernate_" ) || methodInfo.getCodeAttribute() == null ) {
continue;
}
try {
final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
while ( itr.hasNext() ) {
int index = itr.next();
int op = itr.byteAt( index );
if ( op != Opcode.PUTFIELD && op != Opcode.GETFIELD ) {
continue;
}
String fieldName = constPool.getFieldrefName( itr.u16bitAt( index + 1 ) );
String fieldClassName = constPool.getClassInfo( constPool.getFieldrefClass( itr.u16bitAt( index + 1 ) ) );
CtClass targetCtClass = classPool.getCtClass( fieldClassName );
if ( !enhancementContext.isEntityClass( targetCtClass ) && !enhancementContext.isCompositeClass( targetCtClass ) ) {
continue;
}
if ( targetCtClass == aCtClass
|| !enhancementContext.isPersistentField( targetCtClass.getField( fieldName ) )
|| PersistentAttributesHelper.hasAnnotation( targetCtClass, fieldName, Id.class )
|| "this$0".equals( fieldName ) ) {
continue;
}
log.debugf(
"Extended enhancement: Transforming access to field [%s.%s] from method [%s#%s]",
fieldClassName,
fieldName,
aCtClass.getName(),
methodName
);
if ( op == Opcode.GETFIELD ) {
int fieldReaderMethodIndex = constPool.addMethodrefInfo(
constPool.addClassInfo( fieldClassName ),
EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName,
"()" + constPool.getFieldrefType( itr.u16bitAt( index + 1 ) )
);
itr.writeByte( Opcode.INVOKEVIRTUAL, index );
itr.write16bit( fieldReaderMethodIndex, index + 1 );
}
else {
int fieldWriterMethodIndex = constPool.addMethodrefInfo(
constPool.addClassInfo( fieldClassName ),
EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName,
"(" + constPool.getFieldrefType( itr.u16bitAt( index + 1 ) ) + ")V"
);
itr.writeByte( Opcode.INVOKEVIRTUAL, index );
itr.write16bit( fieldWriterMethodIndex, index + 1 );
}
}
methodInfo.getCodeAttribute().setAttribute( MapMaker.make( classPool, methodInfo ) );
}
catch (BadBytecode bb) {
final String msg = String.format(
"Unable to perform extended enhancement in method [%s]",
methodName
);
throw new EnhancementException( msg, bb );
}
catch (NotFoundException nfe) {
final String msg = String.format(
"Unable to perform extended enhancement in method [%s]",
methodName
);
throw new EnhancementException( msg, nfe );
}
}
}
}

View File

@ -1,412 +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.enhance.internal.javassist;
import java.beans.Introspector;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Map;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMember;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.SignatureAttribute;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
/**
* util methods to fetch attribute metadata. consistent for both field and property access types.
*
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
* @see org.hibernate.internal.util.ReflectHelper
*/
public class PersistentAttributesHelper {
private PersistentAttributesHelper() {
}
private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributesHelper.class );
public static boolean hasAnnotation(CtField attribute, Class<? extends Annotation> annotation) {
return getAnnotation( attribute, annotation ) != null;
}
public static boolean hasAnnotation(CtClass ctClass, String attributeName, Class<? extends Annotation> annotation) {
return getAnnotation( ctClass, attributeName, annotation ) != null;
}
public static <T extends Annotation> T getAnnotation(CtField attribute, Class<T> annotation) {
return getAnnotation( attribute.getDeclaringClass(), attribute.getName(), annotation );
}
public static <T extends Annotation> T getAnnotation(CtClass ctClass, String attributeName, Class<T> annotation) {
AccessType classAccessType = getAccessTypeOrNull( ctClass );
CtField field = findFieldOrNull( ctClass, attributeName );
CtMethod getter = findGetterOrNull( ctClass, attributeName );
if ( classAccessType == AccessType.FIELD || ( field != null && getAccessTypeOrNull( field ) == AccessType.FIELD ) ) {
return field == null ? null : getAnnotationOrNull( field, annotation );
}
if ( classAccessType == AccessType.PROPERTY || ( getter != null && getAccessTypeOrNull( getter ) == AccessType.PROPERTY ) ) {
return getter == null ? null : getAnnotationOrNull( getter, annotation );
}
T found = ( getter == null ? null : getAnnotationOrNull( getter, annotation ) );
if ( found == null && field != null ) {
return getAnnotationOrNull( field, annotation );
}
return found;
}
private static <T extends Annotation> T getAnnotationOrNull(CtMember ctMember, Class<T> annotation) {
try {
if ( ctMember.hasAnnotation( annotation ) ) {
return annotation.cast( ctMember.getAnnotation( annotation ) );
}
}
catch (ClassNotFoundException cnfe) {
// should never happen
}
return null;
}
private static AccessType getAccessTypeOrNull(CtMember ctMember) {
Access access = getAnnotationOrNull( ctMember, Access.class );
return access == null ? null : access.value();
}
private static AccessType getAccessTypeOrNull(CtClass ctClass) {
try {
if ( ctClass.hasAnnotation( Access.class ) ) {
return ( (Access) ctClass.getAnnotation( Access.class ) ).value();
}
else {
CtClass extendsClass = ctClass.getSuperclass();
return extendsClass == null ? null : getAccessTypeOrNull( extendsClass );
}
}
catch (ClassNotFoundException e) {
return null;
}
catch (NotFoundException e) {
return null;
}
}
//
/**
* duplicated here to take CtClass instead of Class
* @see org.hibernate.internal.util.ReflectHelper#locateField
*/
private static CtField findFieldOrNull(CtClass ctClass, String propertyName) {
if ( ctClass == null ) {
return null;
}
try {
return ctClass.getField( propertyName );
}
catch ( NotFoundException nsfe ) {
try {
return findFieldOrNull( ctClass.getSuperclass(), propertyName );
}
catch (NotFoundException e) {
return null;
}
}
}
/**
* duplicated here to take CtClass instead of Class
* @see org.hibernate.internal.util.ReflectHelper#findGetterMethod
*/
private static CtMethod findGetterOrNull(CtClass ctClass, String propertyName) {
if ( ctClass == null ) {
return null;
}
CtMethod method = getterOrNull( ctClass, propertyName );
if ( method != null ) {
return method;
}
try {
// check if extends
method = findGetterOrNull( ctClass.getSuperclass(), propertyName );
if ( method != null ) {
return method;
}
// check if implements
for ( CtClass interfaceCtClass : ctClass.getInterfaces() ) {
method = getterOrNull( interfaceCtClass, propertyName );
if ( method != null ) {
return method;
}
}
}
catch (NotFoundException nfe) {
// give up
}
return null;
}
private static CtMethod getterOrNull(CtClass containerClass, String propertyName) {
for ( CtMethod method : containerClass.getDeclaredMethods() ) {
try {
// if the method has parameters, skip it
if ( method.isEmpty() || method.getParameterTypes().length != 0 ) {
continue;
}
}
catch (NotFoundException e) {
continue;
}
final String methodName = method.getName();
// try "get"
if ( methodName.startsWith( "get" ) ) {
String testStdMethod = Introspector.decapitalize( methodName.substring( 3 ) );
String testOldMethod = methodName.substring( 3 );
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
return method;
}
}
// if not "get", then try "is"
if ( methodName.startsWith( "is" ) ) {
String testStdMethod = Introspector.decapitalize( methodName.substring( 2 ) );
String testOldMethod = methodName.substring( 2 );
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
return method;
}
}
}
return null;
}
//
public static boolean isPossibleBiDirectionalAssociation(CtField persistentField) {
return PersistentAttributesHelper.hasAnnotation( persistentField, OneToOne.class ) ||
PersistentAttributesHelper.hasAnnotation( persistentField, OneToMany.class ) ||
PersistentAttributesHelper.hasAnnotation( persistentField, ManyToOne.class ) ||
PersistentAttributesHelper.hasAnnotation( persistentField, ManyToMany.class );
}
public static String getMappedBy(CtField persistentField, CtClass targetEntity, JavassistEnhancementContext context) throws NotFoundException {
final String local = getMappedByFromAnnotation( persistentField );
if ( local == null || local.isEmpty() ) {
return getMappedByFromTargetEntity( persistentField, targetEntity, context );
}
else {
// HHH-13446 - mappedBy from annotation may not be a valid bi-directional association, verify by calling isValidMappedBy()
return isValidMappedBy( persistentField, targetEntity, local, context ) ? local : "";
}
}
private static boolean isValidMappedBy(CtField persistentField, CtClass targetEntity, String mappedBy, JavassistEnhancementContext context) {
try {
CtField f = targetEntity.getField( mappedBy );
return context.isPersistentField( f ) && isAssignable( persistentField.getDeclaringClass(), inferFieldTypeName( f ) );
}
catch ( NotFoundException e ) {
return false;
}
}
private static String getMappedByFromAnnotation(CtField persistentField) {
OneToOne oto = PersistentAttributesHelper.getAnnotation( persistentField, OneToOne.class );
if ( oto != null ) {
return oto.mappedBy();
}
OneToMany otm = PersistentAttributesHelper.getAnnotation( persistentField, OneToMany.class );
if ( otm != null ) {
return otm.mappedBy();
}
// For @ManyToOne associations, mappedBy must come from the @OneToMany side of the association
ManyToMany mtm = PersistentAttributesHelper.getAnnotation( persistentField, ManyToMany.class );
return mtm == null ? "" : mtm.mappedBy();
}
private static String getMappedByFromTargetEntity(
CtField persistentField,
CtClass targetEntity,
JavassistEnhancementContext context) throws NotFoundException {
// get mappedBy value by searching in the fields of the target entity class
for ( CtField f : targetEntity.getDeclaredFields() ) {
if ( context.isPersistentField( f )
&& getMappedByFromAnnotation( f ).equals( persistentField.getName() )
&& isAssignable( persistentField.getDeclaringClass(), inferFieldTypeName( f ) ) ) {
log.debugf(
"mappedBy association for field [%s#%s] is [%s#%s]",
persistentField.getDeclaringClass().getName(),
persistentField.getName(),
targetEntity.getName(),
f.getName()
);
return f.getName();
}
}
return "";
}
public static CtClass getTargetEntityClass(CtClass managedCtClass, CtField persistentField) throws NotFoundException {
// get targetEntity defined in the annotation
try {
OneToOne oto = PersistentAttributesHelper.getAnnotation( persistentField, OneToOne.class );
OneToMany otm = PersistentAttributesHelper.getAnnotation( persistentField, OneToMany.class );
ManyToOne mto = PersistentAttributesHelper.getAnnotation( persistentField, ManyToOne.class );
ManyToMany mtm = PersistentAttributesHelper.getAnnotation( persistentField, ManyToMany.class );
Class<?> targetClass = null;
if ( oto != null ) {
targetClass = oto.targetEntity();
}
if ( otm != null ) {
targetClass = otm.targetEntity();
}
if ( mto != null ) {
targetClass = mto.targetEntity();
}
if ( mtm != null ) {
targetClass = mtm.targetEntity();
}
if ( targetClass != null && targetClass != void.class ) {
return managedCtClass.getClassPool().get( targetClass.getName() );
}
}
catch (NotFoundException ignore) {
}
// infer targetEntity from generic type signature
String inferredTypeName = inferTypeName( managedCtClass, persistentField.getName() );
return inferredTypeName == null ? null : managedCtClass.getClassPool().get( inferredTypeName );
}
/**
* Consistent with hasAnnotation()
*/
private static String inferTypeName(CtClass ctClass, String attributeName ) {
AccessType classAccessType = getAccessTypeOrNull( ctClass );
CtField field = findFieldOrNull( ctClass, attributeName );
CtMethod getter = findGetterOrNull( ctClass, attributeName );
if ( classAccessType == AccessType.FIELD || ( field != null && getAccessTypeOrNull( field ) == AccessType.FIELD ) ) {
return field == null ? null : inferFieldTypeName( field );
}
if ( classAccessType == AccessType.PROPERTY || ( getter != null && getAccessTypeOrNull( getter ) == AccessType.PROPERTY ) ) {
return getter == null ? null : inferMethodTypeName( getter );
}
String found = ( getter == null ? null : inferMethodTypeName( getter ) );
if ( found == null && field != null ) {
return inferFieldTypeName( field );
}
return found;
}
private static String inferFieldTypeName(CtField field) {
try {
if ( field.getFieldInfo2().getAttribute( SignatureAttribute.tag ) == null ) {
return field.getType().getName();
}
return inferGenericTypeName(
field.getType(),
SignatureAttribute.toTypeSignature( field.getGenericSignature() )
);
}
catch (BadBytecode ignore) {
return null;
}
catch (NotFoundException e) {
return null;
}
}
private static String inferMethodTypeName(CtMethod method) {
try {
if ( method.getMethodInfo2().getAttribute( SignatureAttribute.tag ) == null ) {
return method.getReturnType().getName();
}
return inferGenericTypeName(
method.getReturnType(),
SignatureAttribute.toMethodSignature( method.getGenericSignature() ).getReturnType()
);
}
catch (BadBytecode ignore) {
return null;
}
catch (NotFoundException e) {
return null;
}
}
private static String inferGenericTypeName(CtClass ctClass, SignatureAttribute.Type genericSignature) {
// infer targetEntity from generic type signature
if ( isAssignable( ctClass, Collection.class.getName() ) ) {
return ( (SignatureAttribute.ClassType) genericSignature ).getTypeArguments()[0].getType().jvmTypeName();
}
if ( isAssignable( ctClass, Map.class.getName() ) ) {
return ( (SignatureAttribute.ClassType) genericSignature ).getTypeArguments()[1].getType().jvmTypeName();
}
return ctClass.getName();
}
//
public static boolean isAssignable(CtClass thisCtClass, String targetClassName) {
if ( thisCtClass == null ) {
return false;
}
if ( thisCtClass.getName().equals( targetClassName ) ) {
return true;
}
try {
// check if extends
if ( isAssignable( thisCtClass.getSuperclass(), targetClassName ) ) {
return true;
}
// check if implements
for ( CtClass interfaceCtClass : thisCtClass.getInterfaces() ) {
if ( isAssignable( interfaceCtClass, targetClassName ) ) {
return true;
}
}
}
catch (NotFoundException e) {
// keep going
}
return false;
}
public static boolean isAssignable(CtField thisCtField, String targetClassName) {
try {
return isAssignable( thisCtField.getType(), targetClassName );
}
catch (NotFoundException e) {
// keep going
}
return false;
}
}

View File

@ -1,32 +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.enhance.internal.javassist;
import java.lang.annotation.Annotation;
import javassist.CtClass;
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
public class UnloadedCtClass implements UnloadedClass {
private final CtClass ctClass;
public UnloadedCtClass(CtClass ctClass) {
this.ctClass = ctClass;
}
@Override
public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
return ctClass.hasAnnotation( annotationType );
}
@Override
public String getName() {
return ctClass.getName();
}
}

View File

@ -1,32 +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.enhance.internal.javassist;
import java.lang.annotation.Annotation;
import javassist.CtField;
import org.hibernate.bytecode.enhance.spi.UnloadedField;
public class UnloadedCtField implements UnloadedField {
final CtField ctField;
public UnloadedCtField(CtField ctField) {
this.ctField = ctField;
}
@Override
public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
return ctField.hasAnnotation( annotationType );
}
@Override
public String toString() {
return this.ctField.toString();
}
}

View File

@ -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>.
*/
/**
* package containing bytecode enhancement code (internals)
*/
package org.hibernate.bytecode.enhance.internal.javassist;

View File

@ -1,101 +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.Serializable;
import org.hibernate.PropertyAccessException;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.cfg.AvailableSettings;
/**
* The {@link org.hibernate.bytecode.spi.ReflectionOptimizer.AccessOptimizer} implementation for Javassist
* which simply acts as an adapter to the {@link BulkAccessor} class.
*
* @author Steve Ebersole
*/
public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimizer, Serializable {
private static final String PROPERTY_GET_EXCEPTION = String.format(
"exception getting property value with Javassist (set %s to false for more info)",
AvailableSettings.USE_REFLECTION_OPTIMIZER
);
private static final String PROPERTY_SET_EXCEPTION = String.format(
"exception setting property value with Javassist (set %s to false for more info)",
AvailableSettings.USE_REFLECTION_OPTIMIZER
);
private final BulkAccessor bulkAccessor;
private final Class mappedClass;
/**
* Constructs an AccessOptimizerAdapter
*
* @param bulkAccessor The bulk accessor to use
* @param mappedClass The mapped class
*/
public AccessOptimizerAdapter(BulkAccessor bulkAccessor, Class mappedClass) {
this.bulkAccessor = bulkAccessor;
this.mappedClass = mappedClass;
}
@Override
public String[] getPropertyNames() {
return bulkAccessor.getGetters();
}
@Override
public Object[] getPropertyValues(Object object) {
try {
return bulkAccessor.getPropertyValues( object );
}
catch ( Throwable t ) {
throw new PropertyAccessException(
t,
PROPERTY_GET_EXCEPTION,
false,
mappedClass,
getterName( t, bulkAccessor )
);
}
}
@Override
public void setPropertyValues(Object object, Object[] values) {
try {
bulkAccessor.setPropertyValues( object, values );
}
catch ( Throwable t ) {
throw new PropertyAccessException(
t,
PROPERTY_SET_EXCEPTION,
true,
mappedClass,
setterName( t, bulkAccessor )
);
}
}
private static String setterName(Throwable t, BulkAccessor accessor) {
if (t instanceof BulkAccessorException ) {
return accessor.getSetters()[ ( (BulkAccessorException) t ).getIndex() ];
}
else {
return "?";
}
}
private static String getterName(Throwable t, BulkAccessor accessor) {
if (t instanceof BulkAccessorException ) {
return accessor.getGetters()[ ( (BulkAccessorException) t ).getIndex() ];
}
else {
return "?";
}
}
}

View File

@ -1,109 +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.Serializable;
/**
* A JavaBean bulk accessor, which provides methods capable of getting/setting multiple properties
* of a JavaBean at once.
*
* IMPORTANT NOTE!!! Apparently the order of the methods here is important as I think BulkAccessorFactory
* makes use of that information in terms of accessing the constructor. Anyway, when I tried to re-arrange them
* the BulkAccessor creation failed and tests started to fail.
*
* @author Muga Nishizawa
* @author Shigeru Chiba
*/
public abstract class BulkAccessor implements Serializable {
protected Class target;
protected String[] getters, setters;
protected Class[] types;
/**
* Protected access constructor so the generated class has access to it.
*/
protected BulkAccessor() {
}
/**
* Obtains the values of properties of a given bean.
*
* @param bean JavaBean.
* @param values the obtained values are stored in this array.
*/
public abstract void getPropertyValues(Object bean, Object[] values);
/**
* Sets properties of a given bean to specified values.
*
* @param bean JavaBean.
* @param values the values assinged to properties.
*/
public abstract void setPropertyValues(Object bean, Object[] values);
/**
* Returns the values of properties of a given bean.
*
* @param bean JavaBean.
*
* @return The property values
*/
public Object[] getPropertyValues(Object bean) {
final Object[] values = new Object[getters.length];
getPropertyValues( bean, values );
return values;
}
/**
* Returns the types of properties.
*
* @return The property types
*/
public Class[] getPropertyTypes() {
return types.clone();
}
/**
* Returns the setter names of properties.
*
* @return The getter names
*/
public String[] getGetters() {
return getters.clone();
}
/**
* Returns the getter names of the properties.
*
* @return The setter names
*/
public String[] getSetters() {
return setters.clone();
}
/**
* Creates a new instance of <code>BulkAccessor</code>.
* The created instance provides methods for setting/getting
* specified properties at once.
*
* @param beanClass the class of the JavaBeans accessed
* through the created object.
* @param getters the names of setter methods for specified properties.
* @param setters the names of getter methods for specified properties.
* @param types the types of specified properties.
*
* @return The created BulkAccessor
*/
public static BulkAccessor create(
Class beanClass,
String[] getters,
String[] setters,
Class[] types) {
return new BulkAccessorFactory( beanClass, getters, setters, types ).create();
}
}

View File

@ -1,69 +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 org.hibernate.HibernateException;
/**
* An exception thrown while generating a bulk accessor.
*
* @author Muga Nishizawa
* @author modified by Shigeru Chiba
*/
public class BulkAccessorException extends HibernateException {
private final int index;
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
*/
public BulkAccessorException(String message) {
this( message, -1 );
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param index The index of the property that causes an exception.
*/
public BulkAccessorException(String message, int index) {
this( message, index, null );
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param cause The underlying cause
*/
public BulkAccessorException(String message, Exception cause) {
this( message, -1, cause );
}
/**
* Constructs an exception.
*
* @param message Message explaining the exception condition
* @param index The index of the property that causes an exception.
* @param cause The underlying cause
*/
public BulkAccessorException(String message, int index, Exception cause) {
super( message + " : @" + index, cause );
this.index = index;
}
/**
* Returns the index of the property that causes this exception.
*
* @return -1 if the index is not specified.
*/
public int getIndex() {
return this.index;
}
}

View File

@ -1,423 +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.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.Bytecode;
import javassist.bytecode.ClassFile;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.Opcode;
import javassist.bytecode.StackMapTable;
import javassist.util.proxy.FactoryHelper;
import javassist.util.proxy.RuntimeSupport;
/**
* A factory of bulk accessors.
*
* @author Muga Nishizawa
* @author modified by Shigeru Chiba
*/
class BulkAccessorFactory {
private static final String PACKAGE_NAME_PREFIX = "org.javassist.tmp.";
private static final String BULKACESSOR_CLASS_NAME = BulkAccessor.class.getName();
private static final String OBJECT_CLASS_NAME = Object.class.getName();
private static final String GENERATED_GETTER_NAME = "getPropertyValues";
private static final String GENERATED_SETTER_NAME = "setPropertyValues";
private static final String GET_SETTER_DESC = "(Ljava/lang/Object;[Ljava/lang/Object;)V";
private static final String THROWABLE_CLASS_NAME = Throwable.class.getName();
private static final String BULKEXCEPTION_CLASS_NAME = BulkAccessorException.class.getName();
private static int counter;
private Class targetBean;
private String[] getterNames;
private String[] setterNames;
private Class[] types;
public String writeDirectory;
BulkAccessorFactory(
Class target,
String[] getterNames,
String[] setterNames,
Class[] types) {
this.targetBean = target;
this.getterNames = getterNames;
this.setterNames = setterNames;
this.types = types;
this.writeDirectory = null;
}
BulkAccessor create() {
final Method[] getters = new Method[getterNames.length];
final Method[] setters = new Method[setterNames.length];
findAccessors( targetBean, getterNames, setterNames, types, getters, setters );
final Class beanClass;
try {
final ClassFile classfile = make( getters, setters );
final ClassLoader loader = this.getClassLoader();
if ( writeDirectory != null ) {
FactoryHelper.writeFile( classfile, writeDirectory );
}
beanClass = FactoryHelper.toClass( classfile, null, loader, getDomain() );
return (BulkAccessor) this.newInstance( beanClass );
}
catch ( Exception e ) {
throw new BulkAccessorException( e.getMessage(), e );
}
}
private ProtectionDomain getDomain() {
final Class cl;
if ( this.targetBean != null ) {
cl = this.targetBean;
}
else {
cl = this.getClass();
}
return cl.getProtectionDomain();
}
private ClassFile make(Method[] getters, Method[] setters) throws CannotCompileException {
String className = targetBean.getName();
// set the name of bulk accessor.
className = className + "_$$_bulkaccess_" + counter++;
if ( className.startsWith( "java." ) ) {
className = PACKAGE_NAME_PREFIX + className;
}
final ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
classfile.setAccessFlags( AccessFlag.PUBLIC );
addDefaultConstructor( classfile );
addGetter( classfile, getters );
addSetter( classfile, setters );
return classfile;
}
private ClassLoader getClassLoader() {
if ( targetBean != null && targetBean.getName().equals( OBJECT_CLASS_NAME ) ) {
return targetBean.getClassLoader();
}
else {
return getClass().getClassLoader();
}
}
private Object newInstance(Class type) throws Exception {
final BulkAccessor instance = (BulkAccessor) type.newInstance();
instance.target = targetBean;
final int len = getterNames.length;
instance.getters = new String[len];
instance.setters = new String[len];
instance.types = new Class[len];
for ( int i = 0; i < len; i++ ) {
instance.getters[i] = getterNames[i];
instance.setters[i] = setterNames[i];
instance.types[i] = types[i];
}
return instance;
}
/**
* Declares a constructor that takes no parameter.
*
* @param classfile The class descriptor
*
* @throws CannotCompileException Indicates trouble with the underlying Javassist calls
*/
private void addDefaultConstructor(ClassFile classfile) throws CannotCompileException {
final ConstPool constPool = classfile.getConstPool();
final String constructorSignature = "()V";
final MethodInfo constructorMethodInfo = new MethodInfo( constPool, MethodInfo.nameInit, constructorSignature );
final Bytecode code = new Bytecode( constPool, 0, 1 );
// aload_0
code.addAload( 0 );
// invokespecial
code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, constructorSignature );
// return
code.addOpcode( Opcode.RETURN );
constructorMethodInfo.setCodeAttribute( code.toCodeAttribute() );
constructorMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( constructorMethodInfo );
}
private void addGetter(ClassFile classfile, final Method[] getters) throws CannotCompileException {
final ConstPool constPool = classfile.getConstPool();
final int targetBeanConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() );
final String desc = GET_SETTER_DESC;
final MethodInfo getterMethodInfo = new MethodInfo( constPool, GENERATED_GETTER_NAME, desc );
final Bytecode code = new Bytecode( constPool, 6, 4 );
/* | this | bean | args | raw bean | */
if ( getters.length >= 0 ) {
// aload_1 // load bean
code.addAload( 1 );
// checkcast // cast bean
code.addCheckcast( this.targetBean.getName() );
// astore_3 // store bean
code.addAstore( 3 );
for ( int i = 0; i < getters.length; ++i ) {
if ( getters[i] != null ) {
final Method getter = getters[i];
// aload_2 // args
code.addAload( 2 );
// iconst_i // continue to aastore
// growing stack is 1
code.addIconst( i );
final Class returnType = getter.getReturnType();
int typeIndex = -1;
if ( returnType.isPrimitive() ) {
typeIndex = FactoryHelper.typeIndex( returnType );
// new
code.addNew( FactoryHelper.wrapperTypes[typeIndex] );
// dup
code.addOpcode( Opcode.DUP );
}
// aload_3 // load the raw bean
code.addAload( 3 );
final String getterSignature = RuntimeSupport.makeDescriptor( getter );
final String getterName = getter.getName();
if ( this.targetBean.isInterface() ) {
// invokeinterface
code.addInvokeinterface( targetBeanConstPoolIndex, getterName, getterSignature, 1 );
}
else {
// invokevirtual
code.addInvokevirtual( targetBeanConstPoolIndex, getterName, getterSignature );
}
if ( typeIndex >= 0 ) {
// is a primitive type
// invokespecial
code.addInvokespecial(
FactoryHelper.wrapperTypes[typeIndex],
MethodInfo.nameInit,
FactoryHelper.wrapperDesc[typeIndex]
);
}
// aastore // args
code.add( Opcode.AASTORE );
code.growStack( -3 );
}
}
}
// return
code.addOpcode( Opcode.RETURN );
getterMethodInfo.setCodeAttribute( code.toCodeAttribute() );
getterMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( getterMethodInfo );
}
private void addSetter(ClassFile classfile, final Method[] setters) throws CannotCompileException {
final ConstPool constPool = classfile.getConstPool();
final int targetTypeConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() );
final String desc = GET_SETTER_DESC;
final MethodInfo setterMethodInfo = new MethodInfo( constPool, GENERATED_SETTER_NAME, desc );
final Bytecode code = new Bytecode( constPool, 4, 6 );
StackMapTable stackmap = null;
/* | this | bean | args | i | raw bean | exception | */
if ( setters.length > 0 ) {
// required to exception table
int start;
int end;
// iconst_0 // i
code.addIconst( 0 );
// istore_3 // store i
code.addIstore( 3 );
// aload_1 // load the bean
code.addAload( 1 );
// checkcast // cast the bean into a raw bean
code.addCheckcast( this.targetBean.getName() );
// astore 4 // store the raw bean
code.addAstore( 4 );
/* current stack len = 0 */
// start region to handling exception (BulkAccessorException)
start = code.currentPc();
int lastIndex = 0;
for ( int i = 0; i < setters.length; ++i ) {
if ( setters[i] != null ) {
final int diff = i - lastIndex;
if ( diff > 0 ) {
// iinc 3, 1
code.addOpcode( Opcode.IINC );
code.add( 3 );
code.add( diff );
lastIndex = i;
}
}
/* current stack len = 0 */
// aload 4 // load the raw bean
code.addAload( 4 );
// aload_2 // load the args
code.addAload( 2 );
// iconst_i
code.addIconst( i );
// aaload
code.addOpcode( Opcode.AALOAD );
// checkcast
final Class[] setterParamTypes = setters[i].getParameterTypes();
final Class setterParamType = setterParamTypes[0];
if ( setterParamType.isPrimitive() ) {
// checkcast (case of primitive type)
// invokevirtual (case of primitive type)
this.addUnwrapper( code, setterParamType );
}
else {
// checkcast (case of reference type)
code.addCheckcast( setterParamType.getName() );
}
/* current stack len = 2 */
final String rawSetterMethodDesc = RuntimeSupport.makeDescriptor( setters[i] );
if ( !this.targetBean.isInterface() ) {
// invokevirtual
code.addInvokevirtual( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc );
}
else {
// invokeinterface
final Class[] params = setters[i].getParameterTypes();
int size;
if ( params[0].equals( Double.TYPE ) || params[0].equals( Long.TYPE ) ) {
size = 3;
}
else {
size = 2;
}
code.addInvokeinterface( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc, size );
}
}
// end region to handling exception (BulkAccessorException)
end = code.currentPc();
// return
code.addOpcode( Opcode.RETURN );
/* current stack len = 0 */
// register in exception table
final int throwableTypeIndex = constPool.addClassInfo( THROWABLE_CLASS_NAME );
final int handlerPc = code.currentPc();
code.addExceptionHandler( start, end, handlerPc, throwableTypeIndex );
// astore 5 // store exception
code.addAstore( 5 );
// new // BulkAccessorException
code.addNew( BULKEXCEPTION_CLASS_NAME );
// dup
code.addOpcode( Opcode.DUP );
// aload 5 // load exception
code.addAload( 5 );
// iload_3 // i
code.addIload( 3 );
// invokespecial // BulkAccessorException.<init>
final String consDesc = "(Ljava/lang/Throwable;I)V";
code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, consDesc );
// athrow
code.addOpcode( Opcode.ATHROW );
final StackMapTable.Writer writer = new StackMapTable.Writer(32);
final int[] localTags = {
StackMapTable.OBJECT,
StackMapTable.OBJECT,
StackMapTable.OBJECT,
StackMapTable.INTEGER
};
final int[] localData = {
constPool.getThisClassInfo(),
constPool.addClassInfo( "java/lang/Object" ),
constPool.addClassInfo( "[Ljava/lang/Object;" ),
0
};
final int[] stackTags = {
StackMapTable.OBJECT
};
final int[] stackData = {
throwableTypeIndex
};
writer.fullFrame( handlerPc, localTags, localData, stackTags, stackData );
stackmap = writer.toStackMapTable( constPool );
}
else {
// return
code.addOpcode( Opcode.RETURN );
}
final CodeAttribute ca = code.toCodeAttribute();
if ( stackmap != null ) {
ca.setAttribute( stackmap );
}
setterMethodInfo.setCodeAttribute( ca );
setterMethodInfo.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( setterMethodInfo );
}
private void addUnwrapper(Bytecode code, Class type) {
final int index = FactoryHelper.typeIndex( type );
final String wrapperType = FactoryHelper.wrapperTypes[index];
// checkcast
code.addCheckcast( wrapperType );
// invokevirtual
code.addInvokevirtual( wrapperType, FactoryHelper.unwarpMethods[index], FactoryHelper.unwrapDesc[index] );
}
private static void findAccessors(
Class clazz,
String[] getterNames,
String[] setterNames,
Class[] types,
Method[] getters,
Method[] setters) {
final int length = types.length;
if ( setterNames.length != length || getterNames.length != length ) {
throw new BulkAccessorException( "bad number of accessors" );
}
final Class[] getParam = new Class[0];
final Class[] setParam = new Class[1];
for ( int i = 0; i < length; i++ ) {
if ( getterNames[i] != null ) {
final Method getter = findAccessor( clazz, getterNames[i], getParam, i );
if ( getter.getReturnType() != types[i] ) {
throw new BulkAccessorException( "wrong return type: " + getterNames[i], i );
}
getters[i] = getter;
}
if ( setterNames[i] != null ) {
setParam[0] = types[i];
setters[i] = findAccessor( clazz, setterNames[i], setParam, i );
}
}
}
@SuppressWarnings("unchecked")
private static Method findAccessor(Class clazz, String name, Class[] params, int index)
throws BulkAccessorException {
try {
final Method method = clazz.getDeclaredMethod( name, params );
if ( Modifier.isPrivate( method.getModifiers() ) ) {
throw new BulkAccessorException( "private property", index );
}
return method;
}
catch ( NoSuchMethodException e ) {
throw new BulkAccessorException( "cannot find an accessor", index );
}
}
}

View File

@ -1,106 +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.lang.reflect.Modifier;
import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.Enhancer;
import org.hibernate.bytecode.spi.BytecodeProvider;
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
/**
* Bytecode provider implementation for Javassist.
* @deprecated The Javassist based enhancer will be removed soon,
* please use the one based on ByteBuddy (which is the default since
* version 5.3 of Hibernate ORM)
*
* @author Steve Ebersole
*/
@Deprecated
public class BytecodeProviderImpl implements BytecodeProvider {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
BytecodeProviderImpl.class.getName()
);
@Override
public ProxyFactoryFactory getProxyFactoryFactory() {
return new ProxyFactoryFactoryImpl();
}
@Override
public ReflectionOptimizer getReflectionOptimizer(
Class clazz,
String[] getterNames,
String[] setterNames,
Class[] types) {
FastClass fastClass;
BulkAccessor bulkAccessor;
try {
fastClass = FastClass.create( clazz );
bulkAccessor = BulkAccessor.create( clazz, getterNames, setterNames, types );
if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) {
if ( fastClass == null ) {
bulkAccessor = null;
}
else {
//test out the optimizer:
final Object instance = fastClass.newInstance();
bulkAccessor.setPropertyValues( instance, bulkAccessor.getPropertyValues( instance ) );
}
}
}
catch ( Throwable t ) {
fastClass = null;
bulkAccessor = null;
if ( LOG.isDebugEnabled() ) {
int index = 0;
if (t instanceof BulkAccessorException) {
index = ( (BulkAccessorException) t ).getIndex();
}
if ( index >= 0 ) {
LOG.debugf(
"Reflection optimizer disabled for %s [%s: %s (property %s)]",
clazz.getName(),
StringHelper.unqualify( t.getClass().getName() ),
t.getMessage(),
setterNames[index]
);
}
else {
LOG.debugf(
"Reflection optimizer disabled for %s [%s: %s]",
clazz.getName(),
StringHelper.unqualify( t.getClass().getName() ),
t.getMessage()
);
}
}
}
if ( fastClass != null && bulkAccessor != null ) {
return new ReflectionOptimizerImpl(
new InstantiationOptimizerAdapter( fastClass ),
new AccessOptimizerAdapter( bulkAccessor, clazz )
);
}
return null;
}
@Override
public Enhancer getEnhancer(EnhancementContext enhancementContext) {
return new EnhancerImpl( enhancementContext );
}
}

View File

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

View File

@ -1,45 +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.Serializable;
import org.hibernate.InstantiationException;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
/**
* The {@link org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer} implementation for Javassist
* which simply acts as an adapter to the {@link FastClass} class.
*
* @author Steve Ebersole
*/
public class InstantiationOptimizerAdapter implements ReflectionOptimizer.InstantiationOptimizer, Serializable {
private final FastClass fastClass;
/**
* Constructs the InstantiationOptimizerAdapter
*
* @param fastClass The fast class for the class to be instantiated here.
*/
public InstantiationOptimizerAdapter(FastClass fastClass) {
this.fastClass = fastClass;
}
@Override
public Object newInstance() {
try {
return fastClass.newInstance();
}
catch ( Exception e ) {
throw new InstantiationException(
"Could not instantiate entity with Javassist optimizer: ",
fastClass.getJavaClass(),
e
);
}
}
}

View File

@ -1,160 +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.lang.reflect.Method;
import java.util.HashMap;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.Proxy;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.internal.bytebuddy.BasicProxyFactoryImpl;
import org.hibernate.bytecode.spi.BasicProxyFactory;
import org.hibernate.bytecode.spi.ProxyFactoryFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.proxy.pojo.javassist.JavassistProxyFactory;
/**
* A factory for Javassist-based {@link ProxyFactory} instances.
*
* @author Steve Ebersole
*/
public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory {
/**
* Builds a Javassist-based proxy factory.
*
* @return a new Javassist-based proxy factory.
*/
@Override
public ProxyFactory buildProxyFactory(SessionFactoryImplementor sessionFactory) {
return new JavassistProxyFactory();
}
/**
* Constructs a BasicProxyFactoryImpl
*
* @param superClass The abstract super class (or null if none).
* @param interfaces Interfaces to be proxied (or null if none).
* @deprecated use {@link #buildBasicProxyFactory(Class)}
*
* @return The constructed BasicProxyFactoryImpl
*/
@Override
@Deprecated
public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) {
return new BasicProxyFactoryImpl( superClass, interfaces );
}
@Override
public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface) {
if ( superClassOrInterface.isInterface() ) {
return new BasicProxyFactoryImpl( null, new Class[]{ superClassOrInterface } );
}
else {
return new BasicProxyFactoryImpl( superClassOrInterface, null );
}
}
private static class BasicProxyFactoryImpl implements BasicProxyFactory {
private final Class proxyClass;
public BasicProxyFactoryImpl(Class superClass, Class[] interfaces) {
if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) {
throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" );
}
final javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();
factory.setFilter( FINALIZE_FILTER );
if ( superClass != null ) {
factory.setSuperclass( superClass );
}
if ( interfaces != null && interfaces.length > 0 ) {
factory.setInterfaces( interfaces );
}
proxyClass = factory.createClass();
}
public Object getProxy() {
try {
final Proxy proxy = (Proxy) proxyClass.newInstance();
proxy.setHandler( new PassThroughHandler( proxy, proxyClass.getName() ) );
return proxy;
}
catch ( Throwable t ) {
throw new HibernateException( "Unable to instantiated proxy instance" );
}
}
public boolean isInstance(Object object) {
return proxyClass.isInstance( object );
}
}
private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
public boolean isHandled(Method m) {
// skip finalize methods
return !( m.getParameterCount() == 0 && m.getName().equals( "finalize" ) );
}
};
private static class PassThroughHandler implements MethodHandler {
private HashMap data = new HashMap();
private final Object proxiedObject;
private final String proxiedClassName;
public PassThroughHandler(Object proxiedObject, String proxiedClassName) {
this.proxiedObject = proxiedObject;
this.proxiedClassName = proxiedClassName;
}
@SuppressWarnings("unchecked")
public Object invoke(
Object object,
Method method,
Method method1,
Object[] args) throws Exception {
final String name = method.getName();
if ( "toString".equals( name ) ) {
return proxiedClassName + "@" + System.identityHashCode( object );
}
else if ( "equals".equals( name ) ) {
return proxiedObject == object;
}
else if ( "hashCode".equals( name ) ) {
return System.identityHashCode( object );
}
final boolean hasGetterSignature = method.getParameterCount() == 0
&& method.getReturnType() != null;
final boolean hasSetterSignature = method.getParameterCount() == 1
&& ( method.getReturnType() == null || method.getReturnType() == void.class );
if ( name.startsWith( "get" ) && hasGetterSignature ) {
final String propName = name.substring( 3 );
return data.get( propName );
}
else if ( name.startsWith( "is" ) && hasGetterSignature ) {
final String propName = name.substring( 2 );
return data.get( propName );
}
else if ( name.startsWith( "set" ) && hasSetterSignature) {
final String propName = name.substring( 3 );
data.put( propName, args[0] );
return null;
}
else {
// todo : what else to do here?
return null;
}
}
}
}

View File

@ -1,45 +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.Serializable;
import org.hibernate.bytecode.spi.ReflectionOptimizer;
/**
* ReflectionOptimizer implementation for Javassist.
*
* @author Steve Ebersole
*/
public class ReflectionOptimizerImpl implements ReflectionOptimizer, Serializable {
private final InstantiationOptimizer instantiationOptimizer;
private final AccessOptimizer accessOptimizer;
/**
* Constructs a ReflectionOptimizerImpl
*
* @param instantiationOptimizer The instantiation optimizer to use
* @param accessOptimizer The property access optimizer to use.
*/
public ReflectionOptimizerImpl(
InstantiationOptimizer instantiationOptimizer,
AccessOptimizer accessOptimizer) {
this.instantiationOptimizer = instantiationOptimizer;
this.accessOptimizer = accessOptimizer;
}
@Override
public InstantiationOptimizer getInstantiationOptimizer() {
return instantiationOptimizer;
}
@Override
public AccessOptimizer getAccessOptimizer() {
return accessOptimizer;
}
}

View File

@ -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.internal.javassist;

View File

@ -14,7 +14,7 @@ import org.hibernate.service.Service;
* An interface for factories of {@link ProxyFactory proxy factory} instances. * An interface for factories of {@link ProxyFactory proxy factory} instances.
* <p/> * <p/>
* Currently used to abstract from the tuplizer whether we are using Byte Buddy or * Currently used to abstract from the tuplizer whether we are using Byte Buddy or
* Javassist for lazy proxy generation. * possibly another implementation (in the future?) for lazy proxy generation.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */

View File

@ -1375,9 +1375,8 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
*/ */
String CHECK_NULLABILITY = "hibernate.check_nullability"; String CHECK_NULLABILITY = "hibernate.check_nullability";
/** /**
* Pick which bytecode enhancing library to use. Currently supports javassist and bytebuddy, bytebuddy being the default since version 5.3. * Pick which bytecode enhancing library to use. Currently supports only bytebuddy, bytebuddy being the default since version 5.3.
*/ */
String BYTECODE_PROVIDER = "hibernate.bytecode.provider"; String BYTECODE_PROVIDER = "hibernate.bytecode.provider";

View File

@ -346,8 +346,7 @@ public final class Environment implements AvailableSettings {
} }
if ( BYTECODE_PROVIDER_NAME_JAVASSIST.equals( providerName ) ) { if ( BYTECODE_PROVIDER_NAME_JAVASSIST.equals( providerName ) ) {
LOG.warnUsingJavassistBytecodeProviderIsDeprecated(); throw LOG.usingRemovedJavassistBytecodeProvider();
return new org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl();
} }
LOG.bytecodeProvider( providerName ); LOG.bytecodeProvider( providerName );

View File

@ -416,7 +416,6 @@ class PropertyContainer {
private static boolean mustBeSkipped(XProperty property) { private static boolean mustBeSkipped(XProperty property) {
//TODO make those hardcoded tests more portable (through the bytecode provider?) //TODO make those hardcoded tests more portable (through the bytecode provider?)
return property.isAnnotationPresent( Transient.class ) return property.isAnnotationPresent( Transient.class )
|| "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ) || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() );
|| "org.hibernate.bytecode.internal.javassist.FieldHandler".equals( property.getType().getName() );
} }
} }

View File

@ -1860,9 +1860,7 @@ public interface CoreMessageLogger extends BasicLogger {
@Message(value = "Detaching an uninitialized collection with enabled filters from a session: %s", id = 506) @Message(value = "Detaching an uninitialized collection with enabled filters from a session: %s", id = 506)
void enabledFiltersWhenDetachFromSession(String collectionInfoString); void enabledFiltersWhenDetachFromSession(String collectionInfoString);
@LogMessage(level = WARN) @Message(value = "The Javassist based BytecodeProvider has been removed: remove the `hibernate.bytecode.provider` configuration property to switch to the default provider", id = 508)
@Message(value = "The Javassist based BytecodeProvider is deprecated. Please switch to using the ByteBuddy based BytecodeProvider, " + HibernateException usingRemovedJavassistBytecodeProvider();
"which is the default since Hibernate ORM 5.3. The Javassist one will be removed soon.", id = 507)
void warnUsingJavassistBytecodeProviderIsDeprecated();
} }

View File

@ -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.proxy.pojo.javassist;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.proxy.pojo.BasicLazyInitializer;
import org.hibernate.type.CompositeType;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
* A Javassist-based lazy initializer proxy.
*
* @author Muga Nishizawa
*/
public class JavassistLazyInitializer extends BasicLazyInitializer implements MethodHandler {
private static final CoreMessageLogger LOG = messageLogger( JavassistLazyInitializer.class );
private final Class[] interfaces;
private boolean constructed;
public JavassistLazyInitializer(
String entityName,
Class persistentClass,
Class[] interfaces,
Serializable id,
Method getIdentifierMethod,
Method setIdentifierMethod,
CompositeType componentIdType,
SharedSessionContractImplementor session,
boolean overridesEquals) {
super( entityName, persistentClass, id, getIdentifierMethod, setIdentifierMethod, componentIdType, session, overridesEquals );
this.interfaces = interfaces;
}
protected void constructed() {
constructed = true;
}
@Override
public Object invoke(
final Object proxy,
final Method thisMethod,
final Method proceed,
final Object[] args) throws Throwable {
if ( this.constructed ) {
// HHH-10922 - Internal calls to bytecode enhanced methods cause proxy to be initialized
if ( thisMethod.getName().startsWith( "$$_hibernate_" ) ) {
return proceed.invoke( proxy, args );
}
Object result;
try {
result = this.invoke( thisMethod, args, proxy );
}
catch ( Throwable t ) {
throw t instanceof RuntimeException ? t : new Exception( t.getCause() );
}
if ( result == INVOKE_IMPLEMENTATION ) {
Object target = getImplementation();
final Object returnValue;
try {
if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) {
if ( !thisMethod.getDeclaringClass().isInstance( target ) ) {
throw new ClassCastException(
target.getClass().getName()
+ " incompatible with "
+ thisMethod.getDeclaringClass().getName()
);
}
returnValue = thisMethod.invoke( target, args );
}
else {
thisMethod.setAccessible( true );
returnValue = thisMethod.invoke( target, args );
}
if ( returnValue == target ) {
if ( returnValue.getClass().isInstance( proxy ) ) {
return proxy;
}
else {
LOG.narrowingProxy( returnValue.getClass() );
}
}
return returnValue;
}
catch ( InvocationTargetException ite ) {
throw ite.getTargetException();
}
}
else {
return result;
}
}
else {
// while constructor is running
if ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) {
return this;
}
else {
return proceed.invoke( proxy, args );
}
}
}
@Override
protected Object serializableProxy() {
return new SerializableProxy(
getEntityName(),
persistentClass,
interfaces,
getInternalIdentifier(),
( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ),
getSessionFactoryUuid(),
isAllowLoadOutsideTransaction(),
getIdentifierMethod,
setIdentifierMethod,
componentIdType
);
}
}

View File

@ -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.proxy.pojo.javassist;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Set;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.Proxy;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.type.CompositeType;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
* A {@link ProxyFactory} implementation for producing Javassist-based proxies.
*
* @author Muga Nishizawa
*/
public class JavassistProxyFactory implements ProxyFactory, Serializable {
private static final CoreMessageLogger LOG = messageLogger( JavassistProxyFactory.class );
private static final MethodFilter EXCLUDE_FILTER = m -> {
// skip finalize methods and Groovy getMetaClass
return !(
m.getParameterCount() == 0 && m.getName().equals( "finalize" ) || (
m.getName().equals( "getMetaClass" ) &&
m.getReturnType().getName().equals( "groovy.lang.MetaClass" )
)
);
};
private Class persistentClass;
private String entityName;
private Class[] interfaces;
private Method getIdentifierMethod;
private Method setIdentifierMethod;
private CompositeType componentIdType;
private boolean overridesEquals;
private Class proxyClass;
public JavassistProxyFactory() {
}
@Override
public void postInstantiate(
final String entityName,
final Class persistentClass,
final Set<Class> interfaces,
final Method getIdentifierMethod,
final Method setIdentifierMethod,
CompositeType componentIdType) throws HibernateException {
this.entityName = entityName;
this.persistentClass = persistentClass;
this.interfaces = toArray( interfaces );
this.getIdentifierMethod = getIdentifierMethod;
this.setIdentifierMethod = setIdentifierMethod;
this.componentIdType = componentIdType;
this.overridesEquals = ReflectHelper.overridesEquals( persistentClass );
this.proxyClass = buildJavassistProxyFactory().createClass();
}
private Class[] toArray(Set<Class> interfaces) {
if ( interfaces == null ) {
return ArrayHelper.EMPTY_CLASS_ARRAY;
}
return interfaces.toArray( new Class[interfaces.size()] );
}
private javassist.util.proxy.ProxyFactory buildJavassistProxyFactory() {
return buildJavassistProxyFactory(
persistentClass,
interfaces
);
}
public static javassist.util.proxy.ProxyFactory buildJavassistProxyFactory(
final Class persistentClass,
final Class[] interfaces) {
javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory() {
@Override
protected ClassLoader getClassLoader() {
return persistentClass.getClassLoader();
}
};
factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
factory.setInterfaces( interfaces );
factory.setFilter( EXCLUDE_FILTER );
return factory;
}
@Override
public HibernateProxy getProxy(
Serializable id,
SharedSessionContractImplementor session) throws HibernateException {
final JavassistLazyInitializer initializer = new JavassistLazyInitializer(
entityName,
persistentClass,
interfaces,
id,
getIdentifierMethod,
setIdentifierMethod,
componentIdType,
session,
overridesEquals
);
try {
final HibernateProxy proxy = (HibernateProxy) proxyClass.getConstructor().newInstance();
( (Proxy) proxy ).setHandler( initializer );
initializer.constructed();
return proxy;
}
catch (NoSuchMethodException e) {
String logMessage = LOG.bytecodeEnhancementFailedBecauseOfDefaultConstructor( entityName );
LOG.error( logMessage, e );
throw new HibernateException( logMessage, e );
}
catch (Throwable t) {
String logMessage = LOG.bytecodeEnhancementFailed( entityName );
LOG.error( logMessage, t );
throw new HibernateException( logMessage, t );
}
}
public static HibernateProxy deserializeProxy(SerializableProxy serializableProxy) {
final JavassistLazyInitializer initializer = new JavassistLazyInitializer(
serializableProxy.getEntityName(),
serializableProxy.getPersistentClass(),
serializableProxy.getInterfaces(),
serializableProxy.getId(),
resolveIdGetterMethod( serializableProxy ),
resolveIdSetterMethod( serializableProxy ),
serializableProxy.getComponentIdType(),
null,
ReflectHelper.overridesEquals( serializableProxy.getPersistentClass() )
);
final javassist.util.proxy.ProxyFactory factory = buildJavassistProxyFactory(
serializableProxy.getPersistentClass(),
serializableProxy.getInterfaces()
);
// note: interface is assumed to already contain HibernateProxy.class
try {
final Class proxyClass = factory.createClass();
final HibernateProxy proxy = ( HibernateProxy ) proxyClass.newInstance();
( (Proxy) proxy ).setHandler( initializer );
initializer.constructed();
return proxy;
}
catch ( Throwable t ) {
final String message = LOG.bytecodeEnhancementFailed( serializableProxy.getEntityName() );
LOG.error( message, t );
throw new HibernateException( message, t );
}
}
@SuppressWarnings("unchecked")
private static Method resolveIdGetterMethod(SerializableProxy serializableProxy) {
if ( serializableProxy.getIdentifierGetterMethodName() == null ) {
return null;
}
try {
return serializableProxy.getIdentifierGetterMethodClass().getDeclaredMethod( serializableProxy.getIdentifierGetterMethodName() );
}
catch (NoSuchMethodException e) {
throw new HibernateException(
String.format(
Locale.ENGLISH,
"Unable to deserialize proxy [%s, %s]; could not locate id getter method [%s] on entity class [%s]",
serializableProxy.getEntityName(),
serializableProxy.getId(),
serializableProxy.getIdentifierGetterMethodName(),
serializableProxy.getIdentifierGetterMethodClass()
)
);
}
}
@SuppressWarnings("unchecked")
private static Method resolveIdSetterMethod(SerializableProxy serializableProxy) {
if ( serializableProxy.getIdentifierSetterMethodName() == null ) {
return null;
}
try {
return serializableProxy.getIdentifierSetterMethodClass().getDeclaredMethod(
serializableProxy.getIdentifierSetterMethodName(),
serializableProxy.getIdentifierSetterMethodParams()
);
}
catch (NoSuchMethodException e) {
throw new HibernateException(
String.format(
Locale.ENGLISH,
"Unable to deserialize proxy [%s, %s]; could not locate id setter method [%s] on entity class [%s]",
serializableProxy.getEntityName(),
serializableProxy.getId(),
serializableProxy.getIdentifierSetterMethodName(),
serializableProxy.getIdentifierSetterMethodClass()
)
);
}
}
}

View File

@ -1,141 +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.proxy.pojo.javassist;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.hibernate.proxy.AbstractSerializableProxy;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.type.CompositeType;
/**
* Serializable placeholder for Javassist proxies
*/
public final class SerializableProxy extends AbstractSerializableProxy {
private final Class persistentClass;
private final Class[] interfaces;
private final String identifierGetterMethodName;
private final Class identifierGetterMethodClass;
private final String identifierSetterMethodName;
private final Class identifierSetterMethodClass;
private final Class[] identifierSetterMethodParams;
private final CompositeType componentIdType;
/**
* @deprecated use {@link #SerializableProxy(String, Class, Class[], Serializable, Boolean, String, boolean, Method, Method, CompositeType)} instead.
*/
@Deprecated
public SerializableProxy(
String entityName,
Class persistentClass,
Class[] interfaces,
Serializable id,
Boolean readOnly,
Method getIdentifierMethod,
Method setIdentifierMethod,
CompositeType componentIdType) {
this(
entityName, persistentClass, interfaces, id, readOnly, null, false,
getIdentifierMethod, setIdentifierMethod, componentIdType
);
}
public SerializableProxy(
String entityName,
Class persistentClass,
Class[] interfaces,
Serializable id,
Boolean readOnly,
String sessionFactoryUuid,
boolean allowLoadOutsideTransaction,
Method getIdentifierMethod,
Method setIdentifierMethod,
CompositeType componentIdType) {
super( entityName, id, readOnly, sessionFactoryUuid, allowLoadOutsideTransaction );
this.persistentClass = persistentClass;
this.interfaces = interfaces;
if ( getIdentifierMethod != null ) {
identifierGetterMethodName = getIdentifierMethod.getName();
identifierGetterMethodClass = getIdentifierMethod.getDeclaringClass();
}
else {
identifierGetterMethodName = null;
identifierGetterMethodClass = null;
}
if ( setIdentifierMethod != null ) {
identifierSetterMethodName = setIdentifierMethod.getName();
identifierSetterMethodClass = setIdentifierMethod.getDeclaringClass();
identifierSetterMethodParams = setIdentifierMethod.getParameterTypes();
}
else {
identifierSetterMethodName = null;
identifierSetterMethodClass = null;
identifierSetterMethodParams = null;
}
this.componentIdType = componentIdType;
}
@Override
protected String getEntityName() {
return super.getEntityName();
}
@Override
protected Serializable getId() {
return super.getId();
}
protected Class getPersistentClass() {
return persistentClass;
}
protected Class[] getInterfaces() {
return interfaces;
}
protected String getIdentifierGetterMethodName() {
return identifierGetterMethodName;
}
protected Class getIdentifierGetterMethodClass() {
return identifierGetterMethodClass;
}
protected String getIdentifierSetterMethodName() {
return identifierSetterMethodName;
}
protected Class getIdentifierSetterMethodClass() {
return identifierSetterMethodClass;
}
protected Class[] getIdentifierSetterMethodParams() {
return identifierSetterMethodParams;
}
protected CompositeType getComponentIdType() {
return componentIdType;
}
/**
* Deserialization hook. This method is called by JDK deserialization. We use this hook
* to replace the serial form with a live form.
*
* @return The live form.
*/
private Object readResolve() {
HibernateProxy proxy = JavassistProxyFactory.deserializeProxy( this );
afterDeserialization( ( JavassistLazyInitializer ) proxy.getHibernateLazyInitializer() );
return proxy;
}
}

View File

@ -1,34 +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.internal.log.DeprecationLogger;
import org.hibernate.tool.enhance.EnhancementTask;
/**
* This is the legacy Ant-task Hibernate provided historically to
* perform its old-school bytecode instrumentation. That has been replaced wholesale
* with a new approach to bytecode manipulation offering 3 build-time variations for Ant,
* Maven and Gradle.
*
* @author Muga Nishizawa
* @author Steve Ebersole
*
* @deprecated This is the legacy Ant-task Hibernate provided historically to
* perform its old-school bytecode instrumentation. That has been replaced wholesale
* with a new approach to bytecode manipulation offering 3 build-time variations for Ant,
* Maven and Gradle.
*
* @see EnhancementTask
*/
@Deprecated
@SuppressWarnings("unused")
public class InstrumentTask extends EnhancementTask {
public InstrumentTask() {
DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedInstrumentTask( InstrumentTask.class, EnhancementTask.class );
}
}

View File

@ -23,7 +23,6 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.proxy.ProxyFactory; import org.hibernate.proxy.ProxyFactory;
import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory; import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory;
import org.hibernate.proxy.pojo.javassist.JavassistProxyFactory;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.logger.LoggerInspectionRule; import org.hibernate.testing.logger.LoggerInspectionRule;
@ -104,9 +103,6 @@ public class PrivateConstructorTest extends BaseEntityManagerFunctionalTestCase
if ( byteCodeProvider == null || Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) { if ( byteCodeProvider == null || Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) {
return ByteBuddyProxyFactory.class; return ByteBuddyProxyFactory.class;
} }
else if ( Environment.BYTECODE_PROVIDER_NAME_JAVASSIST.equals( byteCodeProvider ) ) {
return JavassistProxyFactory.class;
}
else { else {
throw new UnsupportedOperationException( "Unknown bytecode provider:" + byteCodeProvider ); throw new UnsupportedOperationException( "Unknown bytecode provider:" + byteCodeProvider );
} }

View File

@ -19,7 +19,7 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
/** /**
* Tests if javassist instrumentation is done with the proper classloader for entities with proxy class. The classloader * Tests if instrumentation is done with the proper classloader for entities with proxy class. The classloader
* of {@link HibernateProxy} will not see {@link IPerson}, since it is only accessible from this package. But: the * of {@link HibernateProxy} will not see {@link IPerson}, since it is only accessible from this package. But: the
* classloader of {@link IPerson} will see {@link HibernateProxy}, so instrumentation will only work if this classloader * classloader of {@link IPerson} will see {@link HibernateProxy}, so instrumentation will only work if this classloader
* is chosen for creating the instrumented proxy class. We need to check the class of a loaded object though, since * is chosen for creating the instrumented proxy class. We need to check the class of a loaded object though, since

View File

@ -1,67 +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.javassist;
import java.io.FileNotFoundException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import javassist.CtClass;
import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
*/
public class EnhancerFileNotFoundTest {
@Test
@TestForIssue( jiraKey = "HHH-11307" )
public void test() throws Exception {
Enhancer enhancer = new Enhancer( new DefaultEnhancementContext() );
try {
String resourceName = Hidden.class.getName().replace( '.', '/' ) + ".class";
URL url = getClass().getClassLoader().getResource( resourceName );
if ( url != null ) {
Files.delete( Paths.get( url.toURI() ) );
enhancer.loadCtClassFromClass( Hidden.class );
}
fail( "Should throw FileNotFoundException!" );
} catch ( Exception expected ) {
assertSame( FileNotFoundException.class, expected.getCause().getClass() );
}
}
// --- //
private static class Enhancer extends EnhancerImpl {
public Enhancer(EnhancementContext enhancementContext) {
super( enhancementContext );
}
@Override
// change visibility protected -> public
public CtClass loadCtClassFromClass(Class<?> aClass) {
return super.loadCtClassFromClass( aClass );
}
}
// --- //
private static class Hidden {
}
}

View File

@ -1,83 +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.javassist;
import java.text.ParseException;
import java.util.Date;
/**
* @author Steve Ebersole
*/
public class Bean {
private String someString;
private Long someLong;
private Integer someInteger;
private Date someDate;
private long somelong;
private int someint;
private Object someObject;
public String getSomeString() {
return someString;
}
public void setSomeString(String someString) {
this.someString = someString;
}
public Long getSomeLong() {
return someLong;
}
public void setSomeLong(Long someLong) {
this.someLong = someLong;
}
public Integer getSomeInteger() {
return someInteger;
}
public void setSomeInteger(Integer someInteger) {
this.someInteger = someInteger;
}
public Date getSomeDate() {
return someDate;
}
public void setSomeDate(Date someDate) {
this.someDate = someDate;
}
public long getSomelong() {
return somelong;
}
public void setSomelong(long somelong) {
this.somelong = somelong;
}
public int getSomeint() {
return someint;
}
public void setSomeint(int someint) {
this.someint = someint;
}
public Object getSomeObject() {
return someObject;
}
public void setSomeObject(Object someObject) {
this.someObject = someObject;
}
public void throwException() throws ParseException {
throw new ParseException( "you asked for it...", 0 );
}
}

View File

@ -1,92 +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.javassist;
import java.util.Date;
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.Setter;
/**
* @author Steve Ebersole
*/
public class BeanReflectionHelper {
public static final Object[] TEST_VALUES = new Object[] {
"hello", new Long(1), new Integer(1), new Date(), new Long(1), new Integer(1), new Object()
};
private static final String[] getterNames = new String[7];
private static final String[] setterNames = new String[7];
private static final Class[] types = new Class[7];
static {
final PropertyAccessStrategyBasicImpl propertyAccessStrategy = new PropertyAccessStrategyBasicImpl();
PropertyAccess propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someString" );
Getter getter = propertyAccess.getGetter();
Setter setter = propertyAccess.getSetter();
getterNames[0] = getter.getMethodName();
types[0] = getter.getReturnType();
setterNames[0] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someLong" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[1] = getter.getMethodName();
types[1] = getter.getReturnType();
setterNames[1] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someInteger" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[2] = getter.getMethodName();
types[2] = getter.getReturnType();
setterNames[2] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someDate" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[3] = getter.getMethodName();
types[3] = getter.getReturnType();
setterNames[3] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "somelong" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[4] = getter.getMethodName();
types[4] = getter.getReturnType();
setterNames[4] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someint" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[5] = getter.getMethodName();
types[5] = getter.getReturnType();
setterNames[5] = setter.getMethodName();
propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someObject" );
getter = propertyAccess.getGetter();
setter = propertyAccess.getSetter();
getterNames[6] = getter.getMethodName();
types[6] = getter.getReturnType();
setterNames[6] = setter.getMethodName();
}
public static String[] getGetterNames() {
return getterNames;
}
public static String[] getSetterNames() {
return setterNames;
}
public static Class[] getTypes() {
return types;
}
}

View File

@ -1,30 +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.javassist;
import org.hibernate.bytecode.internal.javassist.BulkAccessor;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
/**
* @author Steve Ebersole
*/
// Extracted from org.hibernate.test.bytecode.ReflectionOptimizerTest.
// I (Yoann) don't know what this tests does, but it's definitely specific to javassist.
public class BulkAccessorTest extends BaseUnitTestCase {
@Test
public void testBulkAccessorDirectly() {
BulkAccessor bulkAccessor = BulkAccessor.create(
Bean.class,
BeanReflectionHelper.getGetterNames(),
BeanReflectionHelper.getSetterNames(),
BeanReflectionHelper.getTypes()
);
}
}

View File

@ -16,10 +16,7 @@ configurations {
} }
dependencies { dependencies {
compile( project( ':hibernate-core-jakarta' ) ) { compile( project( ':hibernate-core-jakarta' ) )
// Exclude access to this to avoid future use.
exclude group: "org.javassist", module: "javassist"
}
jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1',
'commons-cli:commons-cli:1.4', 'commons-cli:commons-cli:1.4',
@ -100,4 +97,4 @@ test {
jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] )
jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] )
} }
} }

View File

@ -11,10 +11,7 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' )
apply plugin: 'hibernate-matrix-testing' apply plugin: 'hibernate-matrix-testing'
dependencies { dependencies {
compile( project( ':hibernate-core' ) ) { compile( project( ':hibernate-core' ) )
// Exclude access to this to avoid future use.
exclude group: "org.javassist", module: "javassist"
}
// TODO HHH-13703: get rid of this dependency // TODO HHH-13703: get rid of this dependency
compile( libraries.dom4j ) compile( libraries.dom4j )

View File

@ -77,7 +77,7 @@ public abstract class EntityTools {
return null; return null;
} }
else if ( HibernateProxy.class.isAssignableFrom( clazz ) ) { else if ( HibernateProxy.class.isAssignableFrom( clazz ) ) {
// Get the source class of Javassist proxy instance. // Get the source class of the proxy instance.
return (Class<T>) clazz.getSuperclass(); return (Class<T>) clazz.getSuperclass();
} }
return clazz; return clazz;

View File

@ -10,9 +10,7 @@ module org.hibernate.orm.integrationtest.java.module.test {
* Main configuration, necessary for real client applications. * Main configuration, necessary for real client applications.
*/ */
opens org.hibernate.orm.integrationtest.java.module.test.entity to opens org.hibernate.orm.integrationtest.java.module.test.entity to org.hibernate.orm.core;
org.hibernate.orm.core,
javassist; // Necessary for javassist, but not for bytebuddy (the default)
requires java.persistence; requires java.persistence;
// IDEA will not find the modules below because it apparently doesn't support automatic module names // IDEA will not find the modules below because it apparently doesn't support automatic module names
@ -31,4 +29,5 @@ module org.hibernate.orm.integrationtest.java.module.test {
opens org.hibernate.orm.integrationtest.java.module.test to junit; opens org.hibernate.orm.integrationtest.java.module.test to junit;
requires junit; requires junit;
} }

View File

@ -21,11 +21,4 @@ sourceSets {
setSrcDirs( ['src/test/java','src/test/resources'] ) setSrcDirs( ['src/test/java','src/test/resources'] )
} }
} }
testJavassist {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
}
}
} }

View File

@ -168,7 +168,6 @@ public class OsgiIntegrationTest {
// // and use defined imports instead // // and use defined imports instead
// probe.setHeader( // probe.setHeader(
// Constants.IMPORT_PACKAGE, // Constants.IMPORT_PACKAGE,
// "javassist.util.proxy"
// + ",javax.persistence" // + ",javax.persistence"
// + ",javax.persistence.spi" // + ",javax.persistence.spi"
// + ",org.h2" // + ",org.h2"

View File

@ -144,8 +144,6 @@ distributions {
from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'jta' } from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'jta' }
from parent.project( 'hibernate-core' ).configurations.runtime from parent.project( 'hibernate-core' ).configurations.runtime
from parent.project( 'hibernate-core' ).configurations.archives.allArtifacts.files.filter{ file -> !file.name.endsWith('-sources.jar') } from parent.project( 'hibernate-core' ).configurations.archives.allArtifacts.files.filter{ file -> !file.name.endsWith('-sources.jar') }
// for now,
from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'javassist' }
} }
// into( 'lib/jpa' ) { // into( 'lib/jpa' ) {

View File

@ -27,7 +27,6 @@ dependencies {
compile( libraries.maven_plugin_tools ) { transitive = false } compile( libraries.maven_plugin_tools ) { transitive = false }
compile( project(':hibernate-core') ) { transitive = false } compile( project(':hibernate-core') ) { transitive = false }
compile( libraries.jpa ) { transitive = false } compile( libraries.jpa ) { transitive = false }
compile( libraries.javassist ) { transitive = false }
compile( libraries.byteBuddy ) { transitive = false } compile( libraries.byteBuddy ) { transitive = false }
compile 'org.codehaus.plexus:plexus-utils:3.0.24' compile 'org.codehaus.plexus:plexus-utils:3.0.24'
compile 'org.sonatype.plexus:plexus-build-api:0.0.7' compile 'org.sonatype.plexus:plexus-build-api:0.0.7'
@ -38,7 +37,6 @@ dependencies {
runtime( project(':hibernate-core') ) runtime( project(':hibernate-core') )
runtime( libraries.jpa ) runtime( libraries.jpa )
runtime( libraries.jta ) runtime( libraries.jta )
runtime( libraries.javassist )
runtime( libraries.byteBuddy ) runtime( libraries.byteBuddy )
runtime 'org.codehaus.plexus:plexus-utils:3.0.24' runtime 'org.codehaus.plexus:plexus-utils:3.0.24'
} }
@ -57,7 +55,6 @@ task processPluginXml(type: Copy) {
+ generateMavenDependency(libraries.antlr)\ + generateMavenDependency(libraries.antlr)\
+ generateMavenDependency(libraries.jta)\ + generateMavenDependency(libraries.jta)\
+ generateMavenDependency(libraries.commons_annotations)\ + generateMavenDependency(libraries.commons_annotations)\
+ generateMavenDependency(libraries.javassist)\
+ generateMavenDependency(libraries.byteBuddy)\ + generateMavenDependency(libraries.byteBuddy)\
+ generateMavenDependency(libraries.logging)\ + generateMavenDependency(libraries.logging)\
+ generateMavenDependency("org.hibernate:hibernate-core:" + project.version)]) + generateMavenDependency("org.hibernate:hibernate-core:" + project.version)])

View File

@ -16,7 +16,6 @@ apply plugin: 'maven'
dependencies { dependencies {
compile( project( ':hibernate-core' ) ) compile( project( ':hibernate-core' ) )
compile( libraries.jpa ) compile( libraries.jpa )
compile( libraries.javassist )
compile( libraries.byteBuddy ) compile( libraries.byteBuddy )
compile gradleApi() compile gradleApi()
compile localGroovy() compile localGroovy()