/**
   * Serialize a {@link IntermediaryResult}.
   *
   * @throws IllegalArgumentException If cannot be serialized
   */
  public static RIntermediateAggregationResult buildRIntermediateAggregationResult(
      IntermediaryResult input) throws IllegalArgumentException {
    if (whitelistedSerializableClassNames == null) initialize();

    RIntermediateAggregationResult res = new RIntermediateAggregationResult();
    res.setOutputColName(input.getOutputColName());
    if (input.getInputColumnType() != null) {
      switch (input.getInputColumnType()) {
        case STRING:
          res.setInputColumnType(RColumnType.STRING);
          break;
        case LONG:
          res.setInputColumnType(RColumnType.LONG);
          break;
        case DOUBLE:
          res.setInputColumnType(RColumnType.DOUBLE);
          break;
      }
    }

    List<RIntermediateAggregationResultValue> values = new ArrayList<>();
    IntermediaryResultValueIterator it = input.createValueIterator();
    while (it.hasNext()) {
      Object valueObject = it.next();

      RIntermediateAggregationResultValue resValue = new RIntermediateAggregationResultValue();

      RValue rvalue = RValueUtil.createRValue(valueObject);
      if (rvalue != null) {
        resValue.setValue(rvalue);
      } else {
        if (!whitelistedSerializableClassNames.contains(valueObject.getClass().getName()))
          // only a shallow check, but better than no check at all.
          throw new IllegalArgumentException(
              "Class " + valueObject.getClass().getName() + " is not whitelisted.");

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
          try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(valueObject);
          }

          resValue.setSerialized(baos.toByteArray());
        } catch (IOException e) {
          logger.error("Could not serialize intermediary result", e);
          throw new IllegalArgumentException("Could not serialize intermediary result", e);
        }
      }

      values.add(resValue);
    }
    res.setValues(values);

    return res;
  }
  /**
   * Deserialize a {@link RIntermediateAggregationResult} to a {@link IntermediaryResult}.
   *
   * @throws IllegalArgumentException if data cannot be deserialized.
   */
  public static IntermediaryResult buildIntermediateAggregationResult(
      RIntermediateAggregationResult input) throws IllegalArgumentException {
    if (whitelistedSerializableClassNames == null) initialize();

    ColumnType type = null;
    if (input.isSetInputColumnType()) {
      switch (input.getInputColumnType()) {
        case LONG:
          type = ColumnType.LONG;
          break;
        case DOUBLE:
          type = ColumnType.DOUBLE;
          break;
        default:
          type = ColumnType.STRING;
          break;
      }
    }

    IntermediaryResult res = new IntermediaryResult(input.getOutputColName(), type);

    for (RIntermediateAggregationResultValue val : input.getValues()) {
      if (val.isSetValue()) {
        res.pushValue(RValueUtil.createValue(val.getValue()));
      } else {
        byte[] serialized = val.getSerialized();
        try (ByteArrayInputStream bais = new ByteArrayInputStream(serialized)) {
          try (ObjectInputStream ois =
              new SafeObjectInputStream(bais, whitelistedSerializableClassNames)) {
            res.pushValue(ois.readObject());
          }
        } catch (IOException | ClassNotFoundException e) {
          logger.error("Could not deserialize intermediate result", e);
          throw new IllegalArgumentException("Could not deserialize intermediate result", e);
        }
      }
    }

    return res;
  }