@SuppressWarnings({"rawtypes", "unchecked"})
    public static ConfigDef enrich(Plugins plugins, ConfigDef baseConfigDef, Map<String, String> props, boolean requireFullConfig) {
        ConfigDef newDef = new ConfigDef(baseConfigDef);
        new EnrichablePlugin<Transformation<?>>("Transformation", TRANSFORMS_CONFIG, TRANSFORMS_GROUP, (Class) Transformation.class,
                props, requireFullConfig) {

            @Override
            protected Set<PluginDesc<Transformation<?>>> plugins() {
                return plugins.transformations();
            }

            @Override
            protected ConfigDef initialConfigDef() {
                // All Transformations get these config parameters implicitly
                return super.initialConfigDef()
                        .define(TransformationStage.PREDICATE_CONFIG, Type.STRING, null, Importance.MEDIUM,
                                "The alias of a predicate used to determine whether to apply this transformation.")
                        .define(TransformationStage.NEGATE_CONFIG, Type.BOOLEAN, false, Importance.MEDIUM,
                                "Whether the configured predicate should be negated.");
            }

            @Override
            protected Stream<Map.Entry<String, ConfigDef.ConfigKey>> configDefsForClass(String typeConfig) {
                return super.configDefsForClass(typeConfig)
                    .filter(entry -> {
                        // The implicit parameters mask any from the transformer with the same name
                        if (TransformationStage.PREDICATE_CONFIG.equals(entry.getKey())
                                || TransformationStage.NEGATE_CONFIG.equals(entry.getKey())) {
                            log.warn("Transformer config {} is masked by implicit config of that name",
                                    entry.getKey());
                            return false;
                        } else {
                            return true;
                        }
                    });
            }

            @Override
            protected ConfigDef config(Transformation<?> transformation) {
                return transformation.config();
            }

            @Override
            protected void validateProps(String prefix) {
                String prefixedNegate = prefix + TransformationStage.NEGATE_CONFIG;
                String prefixedPredicate = prefix + TransformationStage.PREDICATE_CONFIG;
                if (props.containsKey(prefixedNegate) &&
                        !props.containsKey(prefixedPredicate)) {
                    throw new ConfigException("Config '" + prefixedNegate + "' was provided " +
                            "but there is no config '" + prefixedPredicate + "' defining a predicate to be negated.");
                }
            }
        }.enrich(newDef);

        new EnrichablePlugin<Predicate<?>>("Predicate", PREDICATES_CONFIG, PREDICATES_GROUP,
                (Class) Predicate.class, props, requireFullConfig) {
            @Override
            protected Set<PluginDesc<Predicate<?>>> plugins() {
                return plugins.predicates();
            }

            @Override
            protected ConfigDef config(Predicate<?> predicate) {
                return predicate.config();
            }
        }.enrich(newDef);
        return newDef;
    }
@Test
    public void testEnrichedConfigDef() {
        String alias = "hdt";
        String prefix = ConnectorConfig.TRANSFORMS_CONFIG + "." + alias + ".";
        Map<String, String> props = new HashMap<>();
        props.put(ConnectorConfig.TRANSFORMS_CONFIG, alias);
        props.put(prefix + "type", HasDuplicateConfigTransformation.class.getName());
        ConfigDef def = ConnectorConfig.enrich(MOCK_PLUGINS, new ConfigDef(), props, false);
        assertEnrichedConfigDef(def, prefix, HasDuplicateConfigTransformation.MUST_EXIST_KEY, ConfigDef.Type.BOOLEAN);
        assertEnrichedConfigDef(def, prefix, TransformationStage.PREDICATE_CONFIG, ConfigDef.Type.STRING);
        assertEnrichedConfigDef(def, prefix, TransformationStage.NEGATE_CONFIG, ConfigDef.Type.BOOLEAN);
    }