private Instance getChanges(
     Instance in, Function<Instance, Instance> oldFunction, boolean isInput) {
   if (in._isNew()) {
     return in.cloneInstance();
   }
   Instance old = oldFunction.apply(in);
   return prepareChanges(in, old, oldFunction, isInput);
 }
 /**
  * Allocates duplicate IDs to newly inserted instances in this organization to reference it from
  * other instance.
  *
  * @param in
  * @param entityId
  */
 private void allocateDuplicateId(Instance in, MutableLong entityId) {
   if (in == null) {
     return;
   }
   if (in._isNew()) {
     long nextId = IdProvider.prepareID(entityId.longValue(), 0, in._type(), true);
     in._setId(nextId);
     entityId.increment();
   }
   in._visit(
       (inst, isChild) -> {
         if (isChild) {
           allocateDuplicateId((Instance) inst, entityId);
         }
       });
 }
 private void setChanges(
     Instance dest,
     Instance src,
     Function<Instance, Instance> oldFunction,
     long[] changes,
     boolean isInput) {
   AModelType type = InvocationContext.get().getTypeManager().getByPrefix(dest._type());
   List<AIField> fields = type.getAllFields();
   for (AIField f : fields) {
     if (f.getName().equals("id")) {
       dest._setId(src.getId());
       continue;
     }
     // If this field changed
     int index = dest._getPropertyIndex(f.getName());
     if (InstanceImpl._hasBit(changes, index)) {
       if (f.isChild()) {
         setChildValue(dest, src, f, oldFunction, isInput);
       } else {
         Property<?> property = src._get(f.getName());
         if (property == null) {
           continue;
         }
         dest._set(f.getName(), property.getValue());
       }
       dest._markChange(index, null, null);
     }
   }
 }
  private Instance cloneSingleChildValue(
      Instance value,
      Instance dest,
      AIField field,
      Function<Instance, Instance> oldFunction,
      boolean isInput) {
    Instance srcValue = (Instance) value;
    if (!srcValue.isEmbedded()) {
      return getChanges(srcValue, oldFunction, isInput);
    }

    Instance destValue = (Instance) dest._get(field.getName()).getValue();
    if (destValue == null) {
      value = srcValue.cloneInstance();
    } else {
      value = prepareChanges(srcValue, destValue, oldFunction, isInput);
    }
    return value;
  }
  private void setChildValue(
      Instance dest,
      Instance src,
      AIField field,
      Function<Instance, Instance> oldFunction,
      boolean isInput) {
    Object value = src._get(field.getName()).getValue();
    if (field.getType().isCollection()) {
      @SuppressWarnings("unchecked")
      List<Instance> coll = (List<Instance>) value;
      List<Instance> result = new ArrayList<Instance>();
      coll.forEach(i -> result.add(getChanges(i, oldFunction, isInput)));
      value = result;
    } else {
      // Simply clone value with changed properties
      if (value != null) {
        value = cloneSingleChildValue((Instance) value, dest, field, oldFunction, isInput);
      }
    }

    dest._set(field.getName(), value);
  }
  private Instance prepareChanges(
      Instance src, Instance dest, Function<Instance, Instance> oldFunction, boolean isInput) {
    InvocationContext context = InvocationContext.get();
    Instance ch = context.getInstanceProvider().newInstance(src._type());
    ch.markInSavingToDB(true);
    if (isInput) {
      if (context.isInRepRetry()) {
        // If in Replication retry, then version of the input will be
        // very old(invalid). So that make the version id of old
        // object.Otherwise When applying this retried version on server
        // will fail.
        ch._setVersion(dest.getVersion());
      } else {
        ch._setVersion(src.getVersion());
      }
    }
    long[] tempChanges = src._getChangesMarkers();

    long[] allChanges = new long[tempChanges.length];
    Arrays.fill(allChanges, -1);
    src._setChangesMarkers(allChanges);
    long[] changes = src._getChanges(dest);
    src._setChangesMarkers(tempChanges);
    setChanges(ch, isInput ? src : dest, oldFunction, changes, isInput);
    InstanceImpl.copyMarkers(ch._getChangesMarkers(), changes);
    ch._setId(src.getId());
    return ch;
  }