帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

384 lines
13 KiB

/*
* 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 com.fr.third.org.hibernate.bytecode.enhance.internal;
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 com.fr.third.javassist.CannotCompileException;
import com.fr.third.javassist.CtClass;
import com.fr.third.javassist.CtField;
import com.fr.third.javassist.Modifier;
import com.fr.third.javassist.NotFoundException;
import com.fr.third.org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
import com.fr.third.org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker;
import com.fr.third.org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
import com.fr.third.org.hibernate.bytecode.enhance.spi.CollectionTracker;
import com.fr.third.org.hibernate.bytecode.enhance.spi.EnhancementContext;
import com.fr.third.org.hibernate.bytecode.enhance.spi.EnhancementException;
import com.fr.third.org.hibernate.bytecode.enhance.spi.EnhancerConstants;
import com.fr.third.org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
import com.fr.third.org.hibernate.engine.spi.EntityEntry;
import com.fr.third.org.hibernate.engine.spi.ManagedEntity;
import com.fr.third.org.hibernate.engine.spi.PersistentAttributeInterceptable;
import com.fr.third.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(EnhancementContext 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
);
FieldWriter.addField(
managedCtClass,
loadCtClassFromClass( CollectionTracker.class ),
EnhancerConstants.TRACKER_COLLECTION_NAME
);
createDirtyTrackerMethods( managedCtClass );
}
private void createDirtyTrackerMethods(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) {
cce.printStackTrace();
}
}
private List<CtField> collectCollectionFields(CtClass managedCtClass) {
List<CtField> collectionList = new ArrayList<CtField>();
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 ) ) {
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() ) && enhancementContext.isPersistentField( 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 ) ) {
if ( !enhancementContext.isMappedCollection( ctField ) ) {
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) {
cce.printStackTrace();
}
}
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 ) ) {
if ( !enhancementContext.isMappedCollection( ctField ) ) {
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) {
cce.printStackTrace();
}
}
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 ) ) {
if ( !enhancementContext.isMappedCollection( ctField ) ) {
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) {
cce.printStackTrace();
}
}
}