@Override
  public void saveRep(
      final Repository rep,
      final IMetaStore metaStore,
      final ObjectId id_transformation,
      final ObjectId id_step)
      throws KettleException {

    try {

      rep.saveStepAttribute(
          id_transformation, id_step, "CATEGORY_NAME", getModelAnnotationCategory());
      rep.saveStepAttribute(
          id_transformation, id_step, "TARGET_OUTPUT_STEP", getTargetOutputStep());

      // Save model annotations
      if (getModelAnnotations() != null) {

        for (int i = 0; i < getModelAnnotations().size(); i++) {

          final ModelAnnotation<?> modelAnnotation = getModelAnnotations().get(i);

          // Add default name
          if (StringUtils.isBlank(modelAnnotation.getName())) {
            modelAnnotation.setName(UUID.randomUUID().toString()); // backwards compatibility
          }

          rep.saveStepAttribute(
              id_transformation, id_step, i, "ANNOTATION_NAME", modelAnnotation.getName());
          rep.saveStepAttribute(
              id_transformation,
              id_step,
              i,
              "ANNOTATION_FIELD_NAME",
              modelAnnotation.getAnnotation().getField());

          if (modelAnnotation.getType() != null) {
            rep.saveStepAttribute(
                id_transformation,
                id_step,
                i,
                "ANNOTATION_TYPE",
                modelAnnotation.getType().toString());

            final int INDEX = i; // trap index so we can use in inner class
            modelAnnotation.iterateProperties(
                new KeyValueClosure() {
                  @Override
                  public void execute(String key, Serializable serializable) {
                    try {
                      if (serializable != null && StringUtils.isNotBlank(serializable.toString())) {
                        rep.saveStepAttribute(
                            id_transformation,
                            id_step,
                            INDEX,
                            "PROPERTY_VALUE_" + key,
                            serializable.toString());
                      }
                    } catch (KettleException e) {
                      logError(e.getMessage());
                    }
                  }
                });
          }
        }

        rep.saveStepAttribute(
            id_transformation,
            id_step,
            "SHARED_DIMENSION",
            getModelAnnotations().isSharedDimension());
        rep.saveStepAttribute(
            id_transformation, id_step, "DESCRIPTION", getModelAnnotations().getDescription());

        List<DataProvider> dataProviders = getModelAnnotations().getDataProviders();
        if (dataProviders != null && !dataProviders.isEmpty()) {
          for (int dIdx = 0; dIdx < dataProviders.size(); dIdx++) {

            DataProvider dataProvider = dataProviders.get(dIdx);

            // Save Data Provider properties
            rep.saveStepAttribute(
                id_transformation, id_step, dIdx, "DP_NAME", dataProvider.getName());
            rep.saveStepAttribute(
                id_transformation, id_step, dIdx, "DP_SCHEMA_NAME", dataProvider.getSchemaName());
            rep.saveStepAttribute(
                id_transformation, id_step, dIdx, "DP_TABLE_NAME", dataProvider.getTableName());
            rep.saveStepAttribute(
                id_transformation,
                id_step,
                dIdx,
                "DP_DATABASE_META_NAME_REF",
                dataProvider.getDatabaseMetaNameRef());

            List<ColumnMapping> columnMappings = dataProvider.getColumnMappings();
            if (columnMappings != null && !columnMappings.isEmpty()) {

              // Save count for loading
              rep.saveStepAttribute(
                  id_transformation, id_step, "CM_COUNT_" + dIdx, columnMappings.size());

              for (int cIdx = 0; cIdx < columnMappings.size(); cIdx++) {

                ColumnMapping columnMapping = columnMappings.get(cIdx);

                // Save ColumnMapping properties
                rep.saveStepAttribute(
                    id_transformation, id_step, dIdx, "CM_NAME_" + cIdx, columnMapping.getName());
                rep.saveStepAttribute(
                    id_transformation,
                    id_step,
                    dIdx,
                    "CM_COLUMN_NAME_" + cIdx,
                    columnMapping.getColumnName());

                if (columnMapping.getColumnDataType() != null) {
                  rep.saveStepAttribute(
                      id_transformation,
                      id_step,
                      dIdx,
                      "CM_DATA_TYPE_" + cIdx,
                      columnMapping.getColumnDataType().name());
                }
              }
            }
          }
        }
      }

    } catch (Exception e) {
      throw new KettleException(
          BaseMessages.getString(
                  PKG, "ModelAnnotationMeta.Exception.UnableToSaveStepInfoToRepository")
              + id_step,
          e);
    }
  }