HHH-9985 - bytecode enhancer - fix merge use case
This commit is contained in:
parent
463decd245
commit
f759c152e2
|
@ -18,7 +18,8 @@ import javassist.Modifier;
|
||||||
import javassist.NotFoundException;
|
import javassist.NotFoundException;
|
||||||
|
|
||||||
import org.hibernate.bytecode.enhance.internal.tracker.CollectionTracker;
|
import org.hibernate.bytecode.enhance.internal.tracker.CollectionTracker;
|
||||||
import org.hibernate.bytecode.enhance.internal.tracker.SimpleDirtyTracker;
|
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
|
||||||
|
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
|
||||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||||
import org.hibernate.bytecode.enhance.spi.EnhancementException;
|
import org.hibernate.bytecode.enhance.spi.EnhancementException;
|
||||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||||
|
@ -36,8 +37,8 @@ public class EntityEnhancer extends Enhancer {
|
||||||
super( context );
|
super( context );
|
||||||
}
|
}
|
||||||
|
|
||||||
// for very small sizes SimpleDirtyTracker implementation ends up being faster
|
// assuming the number of fields is not very high, SimpleFieldTracker implementation it's the fastest
|
||||||
private static final String TRACKER_IMPL = SimpleDirtyTracker.class.getName();
|
private static final String DIRTY_TRACKER_IMPL = SimpleFieldTracker.class.getName();
|
||||||
|
|
||||||
public void enhance(CtClass managedCtClass) {
|
public void enhance(CtClass managedCtClass) {
|
||||||
// add the ManagedEntity interface
|
// add the ManagedEntity interface
|
||||||
|
@ -107,7 +108,11 @@ public class EntityEnhancer extends Enhancer {
|
||||||
try {
|
try {
|
||||||
managedCtClass.addInterface( classPool.get( SelfDirtinessTracker.class.getName() ) );
|
managedCtClass.addInterface( classPool.get( SelfDirtinessTracker.class.getName() ) );
|
||||||
|
|
||||||
FieldWriter.addField( managedCtClass, classPool.get( TRACKER_IMPL ), EnhancerConstants.TRACKER_FIELD_NAME );
|
FieldWriter.addField(
|
||||||
|
managedCtClass,
|
||||||
|
classPool.get( DIRTY_TRACKER_IMPL ),
|
||||||
|
EnhancerConstants.TRACKER_FIELD_NAME
|
||||||
|
);
|
||||||
FieldWriter.addField(
|
FieldWriter.addField(
|
||||||
managedCtClass,
|
managedCtClass,
|
||||||
classPool.get( CollectionTracker.class.getName() ),
|
classPool.get( CollectionTracker.class.getName() ),
|
||||||
|
@ -124,14 +129,14 @@ public class EntityEnhancer extends Enhancer {
|
||||||
private void createDirtyTrackerMethods(CtClass managedCtClass) {
|
private void createDirtyTrackerMethods(CtClass managedCtClass) {
|
||||||
try {
|
try {
|
||||||
MethodWriter.write(
|
MethodWriter.write(
|
||||||
managedCtClass, "" +
|
managedCtClass,
|
||||||
"public void %1$s(String name) {%n" +
|
"public void %1$s(String name) {%n" +
|
||||||
" if (%2$s == null) { %2$s = new %3$s(); }%n" +
|
" if (%2$s == null) { %2$s = new %3$s(); }%n" +
|
||||||
" %2$s.add(name);%n" +
|
" %2$s.add(name);%n" +
|
||||||
"}",
|
"}",
|
||||||
EnhancerConstants.TRACKER_CHANGER_NAME,
|
EnhancerConstants.TRACKER_CHANGER_NAME,
|
||||||
EnhancerConstants.TRACKER_FIELD_NAME,
|
EnhancerConstants.TRACKER_FIELD_NAME,
|
||||||
TRACKER_IMPL
|
DIRTY_TRACKER_IMPL
|
||||||
);
|
);
|
||||||
|
|
||||||
createCollectionDirtyCheckMethod( managedCtClass );
|
createCollectionDirtyCheckMethod( managedCtClass );
|
||||||
|
@ -139,7 +144,7 @@ public class EntityEnhancer extends Enhancer {
|
||||||
createClearDirtyCollectionMethod( managedCtClass );
|
createClearDirtyCollectionMethod( managedCtClass );
|
||||||
|
|
||||||
MethodWriter.write(
|
MethodWriter.write(
|
||||||
managedCtClass, "" +
|
managedCtClass,
|
||||||
"public String[] %1$s() {%n" +
|
"public String[] %1$s() {%n" +
|
||||||
" if(%3$s == null) {%n" +
|
" if(%3$s == null) {%n" +
|
||||||
" return (%2$s == null) ? new String[0] : %2$s.get();%n" +
|
" return (%2$s == null) ? new String[0] : %2$s.get();%n" +
|
||||||
|
@ -153,12 +158,11 @@ public class EntityEnhancer extends Enhancer {
|
||||||
EnhancerConstants.TRACKER_FIELD_NAME,
|
EnhancerConstants.TRACKER_FIELD_NAME,
|
||||||
EnhancerConstants.TRACKER_COLLECTION_NAME,
|
EnhancerConstants.TRACKER_COLLECTION_NAME,
|
||||||
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
|
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
|
||||||
TRACKER_IMPL
|
DIRTY_TRACKER_IMPL
|
||||||
);
|
);
|
||||||
|
|
||||||
MethodWriter.write(
|
MethodWriter.write(
|
||||||
managedCtClass,
|
managedCtClass,
|
||||||
"" +
|
|
||||||
"public boolean %1$s() {%n" +
|
"public boolean %1$s() {%n" +
|
||||||
" return (%2$s != null && !%2$s.isEmpty()) || %3$s();%n" +
|
" return (%2$s != null && !%2$s.isEmpty()) || %3$s();%n" +
|
||||||
"}",
|
"}",
|
||||||
|
@ -169,7 +173,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
|
|
||||||
MethodWriter.write(
|
MethodWriter.write(
|
||||||
managedCtClass,
|
managedCtClass,
|
||||||
"" +
|
|
||||||
"public void %1$s() {%n" +
|
"public void %1$s() {%n" +
|
||||||
" if (%2$s != null) { %2$s.clear(); }%n" +
|
" if (%2$s != null) { %2$s.clear(); }%n" +
|
||||||
" %3$s();%n" +
|
" %3$s();%n" +
|
||||||
|
@ -213,7 +216,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
|
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
"private boolean %1$s() {%n" +
|
"private boolean %1$s() {%n" +
|
||||||
" if (%2$s == null) {%n" +
|
" if (%2$s == null) {%n" +
|
||||||
" return false;%n" +
|
" return false;%n" +
|
||||||
|
@ -227,7 +229,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
" // collection field [%1$s]%n" +
|
" // 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) { return true; }%n" +
|
||||||
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { return true; }%n",
|
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { return true; }%n",
|
||||||
|
@ -252,12 +253,11 @@ public class EntityEnhancer extends Enhancer {
|
||||||
|
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
"private void %1$s(%3$s tracker) {%n" +
|
"private void %1$s(%3$s tracker) {%n" +
|
||||||
" if (%2$s == null) { return; }%n",
|
" if (%2$s == null) { return; }%n",
|
||||||
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
|
EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME,
|
||||||
EnhancerConstants.TRACKER_COLLECTION_NAME,
|
EnhancerConstants.TRACKER_COLLECTION_NAME,
|
||||||
TRACKER_IMPL
|
DirtyTracker.class.getName()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -265,7 +265,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
" // Collection field [%1$s]%n" +
|
" // 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) { tracker.add(\"%1$s\"); }%n" +
|
||||||
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { tracker.add(\"%1$s\"); }%n",
|
" if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { tracker.add(\"%1$s\"); }%n",
|
||||||
|
@ -290,7 +289,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
|
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
"private void %1$s() {%n" +
|
"private void %1$s() {%n" +
|
||||||
" if (%2$s == null) { %2$s = new %3$s(); }%n",
|
" if (%2$s == null) { %2$s = new %3$s(); }%n",
|
||||||
EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME,
|
EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME,
|
||||||
|
@ -303,7 +301,6 @@ public class EntityEnhancer extends Enhancer {
|
||||||
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
if ( !enhancementContext.isMappedCollection( ctField ) ) {
|
||||||
body.append(
|
body.append(
|
||||||
String.format(
|
String.format(
|
||||||
"" +
|
|
||||||
" // Collection field [%1$s]%n" +
|
" // Collection field [%1$s]%n" +
|
||||||
" if (%1$s == null) { %2$s.add(\"%1$s\", -1); }%n" +
|
" if (%1$s == null) { %2$s.add(\"%1$s\", -1); }%n" +
|
||||||
" else { %2$s.add(\"%1$s\", %1$s.size()); }%n",
|
" else { %2$s.add(\"%1$s\", %1$s.size()); }%n",
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.tracker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to be implemented by dirty trackers, a simplified Set of String.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
|
||||||
|
*/
|
||||||
|
public interface DirtyTracker {
|
||||||
|
|
||||||
|
void add(String name);
|
||||||
|
|
||||||
|
boolean contains(String name);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
boolean isEmpty();
|
||||||
|
|
||||||
|
String[] get();
|
||||||
|
}
|
|
@ -16,14 +16,15 @@ import java.util.Arrays;
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
|
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
|
||||||
*/
|
*/
|
||||||
public final class SimpleDirtyTracker {
|
public final class SimpleFieldTracker implements DirtyTracker {
|
||||||
|
|
||||||
private String[] names;
|
private String[] names;
|
||||||
|
|
||||||
public SimpleDirtyTracker() {
|
public SimpleFieldTracker() {
|
||||||
names = new String[0];
|
names = new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void add(String name) {
|
public void add(String name) {
|
||||||
if ( !contains( name ) ) {
|
if ( !contains( name ) ) {
|
||||||
names = Arrays.copyOf( names, names.length + 1 );
|
names = Arrays.copyOf( names, names.length + 1 );
|
||||||
|
@ -31,6 +32,7 @@ public final class SimpleDirtyTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean contains(String name) {
|
public boolean contains(String name) {
|
||||||
for ( String existing : names ) {
|
for ( String existing : names ) {
|
||||||
if ( existing.equals( name ) ) {
|
if ( existing.equals( name ) ) {
|
||||||
|
@ -40,14 +42,17 @@ public final class SimpleDirtyTracker {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
names = new String[0];
|
names = new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return names.length == 0;
|
return names.length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String[] get() {
|
public String[] get() {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
|
@ -13,14 +13,15 @@ package org.hibernate.bytecode.enhance.internal.tracker;
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
|
* @author <a href="mailto:lbarreiro@redhat.com">Luis Barreiro</a>
|
||||||
*/
|
*/
|
||||||
public final class SortedDirtyTracker {
|
public final class SortedFieldTracker implements DirtyTracker {
|
||||||
|
|
||||||
private String[] names;
|
private String[] names;
|
||||||
|
|
||||||
public SortedDirtyTracker() {
|
public SortedFieldTracker() {
|
||||||
names = new String[0];
|
names = new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void add(String name) {
|
public void add(String name) {
|
||||||
// we do a binary search: even if we don't find the name at least we get the position to insert into the array
|
// we do a binary search: even if we don't find the name at least we get the position to insert into the array
|
||||||
int insert = 0;
|
int insert = 0;
|
||||||
|
@ -41,12 +42,13 @@ public final class SortedDirtyTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String[] newNames = new String[names.length + 1];
|
final String[] newNames = new String[names.length + 1];
|
||||||
System.arraycopy( names, 0, newNames, 0, insert);
|
System.arraycopy( names, 0, newNames, 0, insert );
|
||||||
System.arraycopy( names, insert, newNames, insert + 1, names.length - insert);
|
System.arraycopy( names, insert, newNames, insert + 1, names.length - insert );
|
||||||
newNames[insert] = name;
|
newNames[insert] = name;
|
||||||
names = newNames;
|
names = newNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean contains(String name) {
|
public boolean contains(String name) {
|
||||||
for ( int low = 0, high = names.length - 1; low <= high; ) {
|
for ( int low = 0, high = names.length - 1; low <= high; ) {
|
||||||
final int middle = low + ( ( high - low ) / 2 );
|
final int middle = low + ( ( high - low ) / 2 );
|
||||||
|
@ -66,14 +68,17 @@ public final class SortedDirtyTracker {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
names = new String[0];
|
names = new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return names.length == 0;
|
return names.length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String[] get() {
|
public String[] get() {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
|
@ -11,7 +11,8 @@ package org.hibernate.bytecode.enhance.spi;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EnhancerConstants {
|
public final class EnhancerConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prefix for persistent-field reader methods.
|
* Prefix for persistent-field reader methods.
|
||||||
*/
|
*/
|
||||||
|
@ -141,22 +142,34 @@ public class EnhancerConstants {
|
||||||
*/
|
*/
|
||||||
public static final String TRACKER_COLLECTION_CHANGED_NAME = "$$_hibernate_areCollectionFieldsDirty";
|
public static final String TRACKER_COLLECTION_CHANGED_NAME = "$$_hibernate_areCollectionFieldsDirty";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the field that holds the collection tracker
|
||||||
|
*/
|
||||||
public static final String TRACKER_COLLECTION_NAME = "$$_hibernate_collectionTracker";
|
public static final String TRACKER_COLLECTION_NAME = "$$_hibernate_collectionTracker";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of method to get dirty collection field names
|
* Name of method to get dirty collection field names
|
||||||
*/
|
*/
|
||||||
public static final String TRACKER_COLLECTION_CHANGED_FIELD_NAME = "$$_hibernate_getCollectionFieldDirtyNames";
|
public static final String TRACKER_COLLECTION_CHANGED_FIELD_NAME = "$$_hibernate_getCollectionFieldDirtyNames";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of method to clear dirty attribute on collection fields
|
||||||
|
*/
|
||||||
public static final String TRACKER_COLLECTION_CLEAR_NAME = "$$_hibernate_clearDirtyCollectionNames";
|
public static final String TRACKER_COLLECTION_CLEAR_NAME = "$$_hibernate_clearDirtyCollectionNames";
|
||||||
|
|
||||||
public static final String TRACKER_COMPOSITE_DIRTY_CHECK = "$$_hibernate_areCompositeFieldsDirty";
|
/**
|
||||||
|
* Field to hold the track the owner of the embeddable entity
|
||||||
public static final String TRACKER_COMPOSITE_DIRTY_FIELDS_GETTER = "$$_hibernate_getCompositeDirtyFields";
|
*/
|
||||||
|
|
||||||
public static final String TRACKER_COMPOSITE_FIELD_NAME = "$$_hibernate_compositeOwners";
|
public static final String TRACKER_COMPOSITE_FIELD_NAME = "$$_hibernate_compositeOwners";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to set the owner of the embedded entity
|
||||||
|
*/
|
||||||
public static final String TRACKER_COMPOSITE_SET_OWNER = "$$_hibernate_setOwner";
|
public static final String TRACKER_COMPOSITE_SET_OWNER = "$$_hibernate_setOwner";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to clear the owner of the embedded entity
|
||||||
|
*/
|
||||||
public static final String TRACKER_COMPOSITE_CLEAR_OWNER = "$$_hibernate_clearOwner";
|
public static final String TRACKER_COMPOSITE_CLEAR_OWNER = "$$_hibernate_clearOwner";
|
||||||
|
|
||||||
private EnhancerConstants() {
|
private EnhancerConstants() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ package org.hibernate.bytecode.enhance.spi.interceptor;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.LazyInitializationException;
|
import org.hibernate.LazyInitializationException;
|
||||||
import org.hibernate.bytecode.enhance.internal.tracker.SimpleDirtyTracker;
|
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
|
||||||
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
@ -26,7 +26,7 @@ public class LazyAttributeLoader implements PersistentAttributeInterceptor {
|
||||||
private final Set<String> lazyFields;
|
private final Set<String> lazyFields;
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
|
|
||||||
private final SimpleDirtyTracker initializedFields = new SimpleDirtyTracker();
|
private final SimpleFieldTracker initializedFields = new SimpleFieldTracker();
|
||||||
|
|
||||||
public LazyAttributeLoader(SessionImplementor session, Set<String> lazyFields, String entityName) {
|
public LazyAttributeLoader(SessionImplementor session, Set<String> lazyFields, String entityName) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -58,6 +58,14 @@ public class LazyAttributeLoader implements PersistentAttributeInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLoaded(String attributeName) {
|
||||||
|
initializedFields.add( attributeName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getiInitializedFields() {
|
||||||
|
return initializedFields.get();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "LazyAttributeLoader(entityName=" + entityName + " ,lazyFields=" + lazyFields + ')';
|
return "LazyAttributeLoader(entityName=" + entityName + " ,lazyFields=" + lazyFields + ')';
|
||||||
|
|
|
@ -287,7 +287,7 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
if( entity instanceof SelfDirtinessTracker ) {
|
if( entity instanceof SelfDirtinessTracker ) {
|
||||||
((SelfDirtinessTracker) entity).$$_hibernate_clearDirtyAttributes();
|
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
persistenceContext.getSession()
|
persistenceContext.getSession()
|
||||||
|
@ -342,7 +342,7 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
||||||
private boolean isUnequivocallyNonDirty(Object entity) {
|
private boolean isUnequivocallyNonDirty(Object entity) {
|
||||||
|
|
||||||
if(entity instanceof SelfDirtinessTracker) {
|
if(entity instanceof SelfDirtinessTracker) {
|
||||||
return ((SelfDirtinessTracker) entity).$$_hibernate_hasDirtyAttributes();
|
return ! ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
final CustomEntityDirtinessStrategy customEntityDirtinessStrategy =
|
final CustomEntityDirtinessStrategy customEntityDirtinessStrategy =
|
||||||
|
|
|
@ -32,6 +32,11 @@ public interface SelfDirtinessTracker {
|
||||||
*/
|
*/
|
||||||
String[] $$_hibernate_getDirtyAttributes();
|
String[] $$_hibernate_getDirtyAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds persistent attribute to the set of values that have changed
|
||||||
|
*/
|
||||||
|
void $$_hibernate_trackChange(String attributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the stored dirty attributes
|
* Clear the stored dirty attributes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.ObjectDeletedException;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
import org.hibernate.WrongClassException;
|
import org.hibernate.WrongClassException;
|
||||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||||
|
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoader;
|
||||||
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
import org.hibernate.bytecode.instrumentation.spi.FieldInterceptor;
|
||||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
import org.hibernate.engine.internal.Cascade;
|
import org.hibernate.engine.internal.Cascade;
|
||||||
|
@ -23,6 +24,9 @@ import org.hibernate.engine.spi.CascadingAction;
|
||||||
import org.hibernate.engine.spi.CascadingActions;
|
import org.hibernate.engine.spi.CascadingActions;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
|
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.event.spi.EntityCopyObserver;
|
import org.hibernate.event.spi.EntityCopyObserver;
|
||||||
|
@ -341,6 +345,27 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
|
||||||
interceptor.dirty();
|
interceptor.dirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for enhanced entities, copy over the dirty attributes and the lazy/loaded fields in the interceptor
|
||||||
|
if ( entity instanceof SelfDirtinessTracker && target instanceof SelfDirtinessTracker ) {
|
||||||
|
for ( String fieldName : ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() ) {
|
||||||
|
( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( fieldName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( entity instanceof PersistentAttributeInterceptable
|
||||||
|
&& target instanceof PersistentAttributeInterceptable
|
||||||
|
&& ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor() != null
|
||||||
|
&& ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor() != null ) {
|
||||||
|
|
||||||
|
PersistentAttributeInterceptor entityInterceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor();
|
||||||
|
PersistentAttributeInterceptor targetInterceptor = ( (PersistentAttributeInterceptable) target ).$$_hibernate_getInterceptor();
|
||||||
|
|
||||||
|
if ( entityInterceptor instanceof LazyAttributeLoader && targetInterceptor instanceof LazyAttributeLoader ) {
|
||||||
|
for ( String fieldName : ( (LazyAttributeLoader) entityInterceptor ).getiInitializedFields() ) {
|
||||||
|
( (LazyAttributeLoader) targetInterceptor ).setLoaded( fieldName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) {
|
private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) {
|
||||||
|
|
|
@ -98,6 +98,7 @@ public abstract class DecompileUtils {
|
||||||
}
|
}
|
||||||
if ( interfaceNames.contains( SelfDirtinessTracker.class.getName() ) ) {
|
if ( interfaceNames.contains( SelfDirtinessTracker.class.getName() ) ) {
|
||||||
assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_FIELD_NAME ) );
|
assertTrue( fieldNames.contains( EnhancerConstants.TRACKER_FIELD_NAME ) );
|
||||||
|
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CHANGER_NAME ) );
|
||||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_GET_NAME ) );
|
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_GET_NAME ) );
|
||||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CLEAR_NAME ) );
|
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_CLEAR_NAME ) );
|
||||||
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_HAS_CHANGED_NAME ) );
|
assertTrue( methodNames.contains( EnhancerConstants.TRACKER_HAS_CHANGED_NAME ) );
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.bytecode.enhancement.tracker;
|
package org.hibernate.test.bytecode.enhancement.tracker;
|
||||||
|
|
||||||
import org.hibernate.bytecode.enhance.internal.tracker.SimpleDirtyTracker;
|
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
|
||||||
import org.hibernate.bytecode.enhance.internal.tracker.SortedDirtyTracker;
|
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
|
||||||
|
import org.hibernate.bytecode.enhance.internal.tracker.SortedFieldTracker;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ public class DirtyTrackerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleTracker() {
|
public void testSimpleTracker() {
|
||||||
SimpleDirtyTracker tracker = new SimpleDirtyTracker();
|
DirtyTracker tracker = new SimpleFieldTracker();
|
||||||
assertTrue(tracker.isEmpty());
|
assertTrue(tracker.isEmpty());
|
||||||
assertTrue(tracker.get().length == 0);
|
assertTrue(tracker.get().length == 0);
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ public class DirtyTrackerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSortedTracker() {
|
public void testSortedTracker() {
|
||||||
SortedDirtyTracker tracker = new SortedDirtyTracker();
|
DirtyTracker tracker = new SortedFieldTracker();
|
||||||
assertTrue(tracker.isEmpty());
|
assertTrue(tracker.isEmpty());
|
||||||
assertTrue(tracker.get().length == 0);
|
assertTrue(tracker.get().length == 0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue