protected void configure(Mapping config, T instance, boolean dryrun, ConfigurationContext context)
            throws ConfiguratorException {
        final Set<Attribute<T, ?>> attributes = describe();
        List<Attribute<T, ?>> sortedAttributes =
                attributes.stream().sorted(Configurator.extensionOrdinalSort()).collect(Collectors.toList());
        for (Attribute<T, ?> attribute : sortedAttributes) {

            final String name = attribute.getName();
            CNode sub = removeIgnoreCase(config, name);
            if (sub == null) {
                for (String alias : attribute.aliases) {
                    sub = removeIgnoreCase(config, alias);
                    if (sub != null) {
                        context.warning(
                                sub, "'" + alias + "' is an obsolete attribute name, please use '" + name + "'");
                        break;
                    }
                }
            }

            if (sub != null) {

                if (attribute.isDeprecated()) {
                    context.warning(config, "'" + attribute.getName() + "' is deprecated");
                    if (context.getDeprecated() == ConfigurationContext.Deprecation.reject) {
                        throw new ConfiguratorException("'" + attribute.getName() + "' is deprecated");
                    }
                }

                for (Class<? extends AccessRestriction> r : attribute.getRestrictions()) {
                    if (r == None.class) {
                        continue;
                    }
                    if (r == Beta.class && context.getRestricted() == ConfigurationContext.Restriction.beta) {
                        continue;
                    }
                    context.warning(config, "'" + attribute.getName() + "' is restricted: " + r.getSimpleName());
                    if (context.getRestricted() == ConfigurationContext.Restriction.reject) {
                        throw new ConfiguratorException(
                                "'" + attribute.getName() + "' is restricted: " + r.getSimpleName());
                    }
                }

                final Class k = attribute.getType();
                final Configurator configurator = context.lookupOrFail(k);

                final Object valueToSet;
                if (attribute.isMultiple()) {
                    List<Object> values = new ArrayList<>();
                    for (CNode o : sub.asSequence()) {
                        Object value = dryrun ? configurator.check(o, context) : configurator.configure(o, context);
                        values.add(value);
                    }
                    valueToSet = values;
                } else {
                    valueToSet = dryrun ? configurator.check(sub, context) : configurator.configure(sub, context);
                }

                if (!dryrun) {
                    try {
                        ((Attribute) attribute)
                                .setValue(instance, valueToSet); // require type erasure to set Object vs ?
                    } catch (Exception ex) {
                        throw new ConfiguratorException(configurator, "Failed to set attribute " + attribute, ex);
                    }
                }
            }
        }

        handleUnknown(config, context);
    }
Run configuration process on the target instance
@param config configuration to apply. Can be partial if {@link #instance(Mapping, ConfigurationContext)} did already used some entries
@param instance target instance to configure
@param dryrun only check configuration is valid regarding target component. Don't actually apply changes to jenkins controller instance
@param context Fully configured Jenkins object used as the starting point for this configuration.
@throws ConfiguratorException something went wrong...
plugin/src/main/java/io/jenkins/plugins/casc/BaseConfigurator.java