Program: 5838
Project: 5838
Buggy source:
/** 
 * @private Merge an entity coming from the server in the context
 * @param obj external entity
 * @param previous previously existing object in the context (null if no existing object)
 * @param expr current path from the context
 * @param parent parent object for collections
 * @param propertyName propertyName from the owner object
 * @return merged entity (=== previous when previous not null)
 */
private Object mergeEntity(MergeContext mergeContext,final Object obj,Object previous,Expression expr,Object parent,String propertyName){
  if (obj != null || previous != null)   log.debug("String_Node_Str",ObjectUtil.toString(obj),ObjectUtil.toString(previous),obj == previous ? "String_Node_Str" : "String_Node_Str");
  Object dest=obj;
  Object p=null;
  if (obj instanceof Lazyable && !((Lazyable)obj).isInitialized()) {
    final EntityDescriptor desc=PersistenceManager.getEntityDescriptor(obj);
    if (desc.getIdPropertyName() != null) {
      p=entitiesByUid.find(new Matcher(){
        public boolean match(        Object o){
          return o.getClass().getName().equals(obj.getClass().getName()) && dataManager.getProperty(obj,desc.getIdPropertyName()).equals(dataManager.getProperty(o,desc.getIdPropertyName()));
        }
      }
);
      if (p != null) {
        previous=p;
        dest=previous;
      }
    }
  }
 else   if (obj instanceof Identifiable) {
    p=entitiesByUid.get(obj.getClass().getName() + "String_Node_Str" + ((Identifiable)obj).getUid());
    if (p != null) {
      if (obj == p)       return obj;
      previous=p;
      dest=previous;
    }
  }
  if (dest != previous && previous != null && (PersistenceManager.objectEquals(dataManager,previous,obj) || (parent != null && !(previous instanceof Identifiable))))   dest=previous;
  if (dest == obj && p == null && obj != null && mergeContext.getSourceEntityManager() != null) {
    try {
      dest=ClassUtil.newInstance(obj.getClass(),Object.class);
      if (obj instanceof Identifiable)       ((Identifiable)dest).setUid(((Identifiable)obj).getUid());
    }
 catch (    Exception e) {
      throw new RuntimeException("String_Node_Str" + obj.getClass(),e);
    }
  }
  if (obj instanceof Lazyable && !((Lazyable)obj).isInitialized() && PersistenceManager.objectEquals(dataManager,previous,obj)) {
    EntityDescriptor desc=PersistenceManager.getEntityDescriptor(obj);
    if (desc.getVersionPropertyName() != null) {
      log.debug("String_Node_Str");
      dirtyCheckContext.markNotDirty(previous,null);
      return previous;
    }
  }
  if (dest instanceof Lazyable && !((Lazyable)dest).isInitialized())   log.debug("String_Node_Str",dest.toString());
  if (dest != null && dest instanceof Identifiable && dest == obj) {
    log.debug("String_Node_Str",obj.toString(),this.id);
  }
  boolean fromCache=(p != null && dest == p);
  if (!fromCache && dest instanceof Identifiable)   entitiesByUid.put((Identifiable)dest);
  mergeContext.putInCache(obj,dest);
  boolean ignore=false;
  if (dest instanceof Identifiable) {
    EntityDescriptor desc=PersistenceManager.getEntityDescriptor(dest);
    if (mergeContext.isUninitializing() && parent instanceof Identifiable && propertyName != null) {
      if (desc.getVersionPropertyName() != null && dataManager.getProperty(obj,desc.getVersionPropertyName()) != null && PersistenceManager.getEntityDescriptor(parent).isLazy(propertyName)) {
        if (defineProxy(desc,dest,obj))         return dest;
      }
    }
    attachEntity((Identifiable)dest,false);
    if (previous != null && dest == previous) {
      if (desc.getVersionPropertyName() != null && !mergeContext.isResolvingConflict()) {
        Number newVersion=(Number)dataManager.getProperty(obj,desc.getVersionPropertyName());
        Number oldVersion=(Number)dataManager.getProperty(dest,desc.getVersionPropertyName());
        if ((newVersion != null && oldVersion != null && newVersion.longValue() < oldVersion.longValue() || (newVersion == null && oldVersion != null))) {
          log.warn("String_Node_Str",dest.toString(),oldVersion,newVersion);
          ignore=true;
        }
 else         if ((newVersion != null && oldVersion != null && newVersion.longValue() > oldVersion.longValue()) || (newVersion != null && oldVersion == null)) {
          mergeContext.markVersionChanged(dest);
          if (mergeContext.getExternalDataSessionId() != null && dirtyCheckContext.isEntityChanged((Identifiable)dest)) {
            log.error("String_Node_Str",dest.toString(),oldVersion,newVersion);
            if (dirtyCheckContext.checkAndMarkNotDirty((Identifiable)dest,(Identifiable)obj)) {
              mergeContext.addConflict((Identifiable)dest,(Identifiable)obj);
              ignore=true;
            }
 else             mergeContext.setMergeUpdate(true);
          }
 else           mergeContext.setMergeUpdate(true);
        }
 else {
          if (dirtyCheckContext.isEntityChanged((Identifiable)dest))           mergeContext.setMergeUpdate(false);
 else           mergeContext.setMergeUpdate(true);
        }
      }
 else       if (!mergeContext.isResolvingConflict())       mergeContext.markVersionChanged(dest);
    }
 else     mergeContext.markVersionChanged(dest);
    if (!ignore)     defaultMerge(mergeContext,obj,dest,expr,parent,propertyName);
  }
 else   defaultMerge(mergeContext,obj,dest,expr,parent,propertyName);
  if (dest != null && !ignore && !mergeContext.isResolvingConflict()) {
    if (mergeContext.isMergeUpdate() && mergeContext.hasVersionChanged(dest))     dirtyCheckContext.markNotDirty(dest,null);
 else     if (dest instanceof Identifiable && obj instanceof Identifiable)     dirtyCheckContext.checkAndMarkNotDirty((Identifiable)dest,(Identifiable)obj);
  }
  if (dest != null)   log.debug("String_Node_Str",dest.toString());
  dataManager.startTracking(dest,parent);
  return dest;
}

Fixed version (ground truth):
/** 
 * @private Merge an entity coming from the server in the context
 * @param obj external entity
 * @param previous previously existing object in the context (null if no existing object)
 * @param expr current path from the context
 * @param parent parent object for collections
 * @param propertyName propertyName from the owner object
 * @return merged entity (=== previous when previous not null)
 */
private Object mergeEntity(MergeContext mergeContext,final Object obj,Object previous,Expression expr,Object parent,String propertyName){
  if (obj != null || previous != null)   log.debug("String_Node_Str",ObjectUtil.toString(obj),ObjectUtil.toString(previous),obj == previous ? "String_Node_Str" : "String_Node_Str");
  Object dest=obj;
  Object p=null;
  if (obj instanceof Lazyable && !((Lazyable)obj).isInitialized()) {
    final EntityDescriptor desc=PersistenceManager.getEntityDescriptor(obj);
    if (desc.getIdPropertyName() != null) {
      p=entitiesByUid.find(new Matcher(){
        public boolean match(        Object o){
          return o.getClass().getName().equals(obj.getClass().getName()) && dataManager.getProperty(obj,desc.getIdPropertyName()).equals(dataManager.getProperty(o,desc.getIdPropertyName()));
        }
      }
);
      if (p != null) {
        previous=p;
        dest=previous;
      }
    }
  }
 else   if (obj instanceof Identifiable) {
    p=entitiesByUid.get(obj.getClass().getName() + "String_Node_Str" + ((Identifiable)obj).getUid());
    if (p != null) {
      if (obj == p)       return obj;
      previous=p;
      dest=previous;
    }
  }
  if (dest != previous && previous != null && (PersistenceManager.objectEquals(dataManager,previous,obj) || (parent != null && !(previous instanceof Identifiable))))   dest=previous;
  if (dest == obj && p == null && obj != null && mergeContext.getSourceEntityManager() != null) {
    try {
      dest=ClassUtil.newInstance(obj.getClass(),Object.class);
      if (obj instanceof Identifiable)       ((Identifiable)dest).setUid(((Identifiable)obj).getUid());
    }
 catch (    Exception e) {
      throw new RuntimeException("String_Node_Str" + obj.getClass(),e);
    }
  }
  if (obj instanceof Lazyable && !((Lazyable)obj).isInitialized() && PersistenceManager.objectEquals(dataManager,previous,obj)) {
    EntityDescriptor desc=PersistenceManager.getEntityDescriptor(obj);
    if (desc.getVersionPropertyName() != null) {
      log.debug("String_Node_Str");
      dirtyCheckContext.markNotDirty(previous,null);
      return previous;
    }
  }
  if (dest instanceof Lazyable && !((Lazyable)dest).isInitialized())   log.debug("String_Node_Str",dest.toString());
  if (dest != null && dest instanceof Identifiable && dest == obj) {
    log.debug("String_Node_Str",obj.toString(),this.id);
  }
  boolean fromCache=(p != null && dest == p);
  if (!fromCache && dest instanceof Identifiable)   entitiesByUid.put((Identifiable)dest);
  mergeContext.putInCache(obj,dest);
  boolean ignore=false;
  if (dest instanceof Identifiable) {
    EntityDescriptor desc=PersistenceManager.getEntityDescriptor(dest);
    if (mergeContext.isUninitializing() && parent instanceof Identifiable && propertyName != null) {
      if (desc.getVersionPropertyName() != null && dataManager.getProperty(obj,desc.getVersionPropertyName()) != null && PersistenceManager.getEntityDescriptor(parent).isLazy(propertyName)) {
        if (defineProxy(desc,dest,obj))         return dest;
      }
    }
    attachEntity((Identifiable)dest,false);
    if (previous != null && dest == previous) {
      if (desc.getVersionPropertyName() != null && !mergeContext.isResolvingConflict()) {
        Number newVersion=(Number)dataManager.getProperty(obj,desc.getVersionPropertyName());
        Number oldVersion=(Number)dataManager.getProperty(dest,desc.getVersionPropertyName());
        if ((newVersion != null && oldVersion != null && newVersion.longValue() < oldVersion.longValue() || (newVersion == null && oldVersion != null))) {
          log.warn("String_Node_Str",dest.toString(),oldVersion,newVersion);
          ignore=true;
        }
 else         if ((newVersion != null && oldVersion != null && newVersion.longValue() > oldVersion.longValue()) || (newVersion != null && oldVersion == null)) {
          mergeContext.markVersionChanged(dest);
          if (mergeContext.getExternalDataSessionId() != null && dirtyCheckContext.isEntityChanged((Identifiable)dest)) {
            log.error("String_Node_Str",dest.toString(),oldVersion,newVersion);
            if (dirtyCheckContext.checkAndMarkNotDirty((Identifiable)dest,(Identifiable)obj)) {
              mergeContext.addConflict((Identifiable)dest,(Identifiable)obj);
              ignore=true;
            }
 else             mergeContext.setMergeUpdate(true);
          }
 else           mergeContext.setMergeUpdate(true);
        }
 else {
          if (dirtyCheckContext.isEntityChanged((Identifiable)dest))           mergeContext.setMergeUpdate(false);
 else           mergeContext.setMergeUpdate(true);
        }
      }
 else       if (!mergeContext.isResolvingConflict())       mergeContext.markVersionChanged(dest);
    }
 else     mergeContext.markVersionChanged(dest);
    if (!ignore)     defaultMerge(mergeContext,obj,dest,expr,parent,propertyName);
  }
 else   defaultMerge(mergeContext,obj,dest,expr,parent,propertyName);
  if (dest != null && !ignore && !mergeContext.isResolvingConflict()) {
    if (mergeContext.isMergeUpdate() && ((dest instanceof Identifiable && mergeContext.hasVersionChanged(dest)) || (!(dest instanceof Identifiable) && parent instanceof Identifiable && mergeContext.hasVersionChanged(parent))))     dirtyCheckContext.markNotDirty(dest,dest instanceof Identifiable ? null : (Identifiable)parent);
 else     if (dest instanceof Identifiable && obj instanceof Identifiable)     dirtyCheckContext.checkAndMarkNotDirty((Identifiable)dest,(Identifiable)obj);
  }
  if (dest != null)   log.debug("String_Node_Str",dest.toString());
  dataManager.startTracking(dest,parent);
  return dest;
}