public ArrayAddExpressionEvaluator(
     JsonNodeFactory factory, FieldTreeNode context, ArrayAddExpression expr) {
   this.factory = factory;
   if (expr.getOp() == UpdateOperator._insert) {
     // Path should include an index
     if (expr.getField().isIndex(expr.getField().numSegments() - 1)) {
       arrayField = expr.getField().prefix(-1);
       insertionIndex = expr.getField().getIndex(expr.getField().numSegments() - 1);
     } else {
       throw new EvaluationError(CrudConstants.ERR_REQUIRED_INSERTION_INDEX + expr.getField());
     }
   } else {
     arrayField = expr.getField();
     insertionIndex = -1;
   }
   if (arrayField.nAnys() > 0) {
     throw new EvaluationError(CrudConstants.ERR_PATTERN_NOT_EXPECTED + arrayField);
   }
   FieldTreeNode ftn = context.resolve(arrayField);
   if (ftn instanceof ArrayField) {
     fieldMd = (ArrayField) ftn;
     // Array size field should be at the same level as the array field
     MutablePath abs = new MutablePath();
     fieldMd.getFullPath(abs);
     absArrayField = abs.mutableCopy();
     abs.setLast(abs.getLast() + "#");
     // At this point, arraySizeField is derived from metadata,
     // so it has * as array indexes
     arraySizeField = abs.immutableCopy();
     values = new ArrayList<>(expr.getValues().size());
     initializeArrayField(context, expr);
   } else {
     throw new EvaluationError(CrudConstants.ERR_REQUIRED_ARRAY + arrayField);
   }
 }
  private void initializeArrayField(FieldTreeNode context, ArrayAddExpression expr) {
    for (RValueExpression rvalue : expr.getValues()) {
      Path refPath = null;
      FieldTreeNode refMd = null;
      if (rvalue.getType() == RValueExpression.RValueType._dereference) {
        refPath = rvalue.getPath();
        refMd = context.resolve(refPath);
        if (refMd == null) {
          throw new EvaluationError(CrudConstants.ERR_INVALID_DEREFERENCE + refPath);
        }
      }

      ArrayElement element = fieldMd.getElement();
      validateArrayElement(element, refMd, rvalue, refPath);

      values.add(
          new RValueData(
              refPath,
              refMd == null ? null : refMd.getType(),
              rvalue.getValue(),
              rvalue.getType()));
    }
  }