Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.bytecode.enhance.internal.javassist.PersistentAttributesEnhancer Maven / Gradle / Ivy
/*
* 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 .
*/
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 Luis Barreiro
*/
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 attrDescriptorMap = new IdentityHashMap();
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 persistentFieldList = new ArrayList();
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 collectInheritPersistentFields(CtClass managedCtClass) {
if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) {
return Collections.emptyList();
}
try {
CtClass managedCtSuperclass = managedCtClass.getSuperclass();
if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) {
return collectInheritPersistentFields( managedCtSuperclass );
}
log.debugf( "Found @MappedSuperclass %s to collectPersistenceFields", managedCtSuperclass.getName() );
List persistentFieldList = new ArrayList();
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(
"Could not find type of bi-directional association for field [%s#%s]",
managedCtClass.getName(),
persistentField.getName()
);
return;
}
final String mappedBy = PersistentAttributesHelper.getMappedBy( persistentField, targetEntity, enhancementContext );
if ( mappedBy == null || mappedBy.isEmpty() ) {
log.infof(
"Could not find bi-directional association for field [%s#%s]",
managedCtClass.getName(),
persistentField.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 ConcurrentModException
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 for field [%s#%s] not managed: @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 );
// cleanup previous owner
fieldWriter.insertBefore(
String.format(
"if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%1$s\"); }%n",
persistentField.getName(),
CompositeTracker.class.getName(),
EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER
)
);
// trigger track changes
fieldWriter.insertAfter(
String.format(
"if (%1$s != null) { ((%2$s) %1$s).%4$s(\"%1$s\", (%3$s) this); }%n" +
"%5$s(\"%1$s\");",
persistentField.getName(),
CompositeTracker.class.getName(),
CompositeOwner.class.getName(),
EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER,
EnhancerConstants.TRACKER_CHANGER_NAME
)
);
}
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 have a 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 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 );
}
}
}
}