All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jbock.annotated.AnnotatedMethodsBuilder Maven / Gradle / Ivy

There is a newer version: 5.18
Show newest version
package net.jbock.annotated;

import io.jbock.util.Either;
import io.jbock.util.Eithers;
import net.jbock.common.EnumName;
import net.jbock.common.ValidationFailure;
import net.jbock.processor.SourceElement;

import javax.lang.model.element.Name;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static io.jbock.util.Either.right;
import static java.util.stream.Collectors.toList;

final class AnnotatedMethodsBuilder {

    private static final Comparator INDEX_COMPARATOR =
            Comparator.comparingInt(AnnotatedParameter::index);

    private final Step5 step5;
    private final List repeatablePositionalParameters;

    private AnnotatedMethodsBuilder(
            Step5 step5,
            List repeatablePositionalParameters) {
        this.step5 = step5;
        this.repeatablePositionalParameters = repeatablePositionalParameters;
    }

    static Step1 builder(List methods) {
        return new Step1(methods);
    }

    static final class Step1 {
        private final List methods;

        Step1(List methods) {
            this.methods = methods;
        }

        Step2 sourceElement(SourceElement sourceElement) {
            return new Step2(methods, createEnumNames(methods), sourceElement);
        }
    }

    private static Map createEnumNames(List methods) {
        Set names = new HashSet<>();
        Map result = new HashMap<>();
        for (Executable method : methods) {
            EnumName enumName = EnumName.create(method.simpleName().toString());
            while (names.contains(enumName)) {
                enumName = enumName.makeLonger();
            }
            names.add(enumName);
            result.put(method.simpleName(), enumName);
        }
        return result;
    }

    static final class Step2 {

        private final List methods;
        private final Map enumNames;
        private final SourceElement sourceElement;

        Step2(List methods,
              Map enumNames,
              SourceElement sourceElement) {
            this.methods = methods;
            this.enumNames = enumNames;
            this.sourceElement = sourceElement;
        }

        Map enumNames() {
            return enumNames;
        }

        List methods() {
            return methods;
        }

        Step3 withAnnotatedMethods(List annotatedMethods) {
            return new Step3(this, annotatedMethods);
        }
    }

    static final class Step3 {

        private final Step2 step2;
        private final List annotatedMethods;

        Step3(Step2 step2, List annotatedMethods) {
            this.step2 = step2;
            this.annotatedMethods = annotatedMethods;
        }

        Step4 withNamedOptions() {
            List namedOptions = annotatedMethods.stream()
                    .flatMap(AnnotatedMethod::asAnnotatedOption)
                    .collect(toList());
            return new Step4(this, namedOptions);
        }
    }

    static final class Step4 {

        private final Step3 step3;
        private final List namedOptions;

        Step4(Step3 step3, List namedOptions) {
            this.step3 = step3;
            this.namedOptions = namedOptions;
        }

        Step5 withPositionalParameters() {
            List positionalParameters = step3.annotatedMethods.stream()
                    .flatMap(AnnotatedMethod::asAnnotatedParameter)
                    .sorted(INDEX_COMPARATOR)
                    .collect(toList());
            return new Step5(this, positionalParameters);
        }
    }

    static final class Step5 {

        private final Step4 step4;
        private final List positionalParameters;

        Step5(Step4 step4, List positionalParameters) {
            this.step4 = step4;
            this.positionalParameters = positionalParameters;
        }

        AnnotatedMethodsBuilder withRepeatablePositionalParameters() {
            List repeatablePositionalParameters = step4.step3.annotatedMethods.stream()
                    .flatMap(AnnotatedMethod::asAnnotatedParameters)
                    .collect(toList());
            return new AnnotatedMethodsBuilder(this, repeatablePositionalParameters);
        }
    }

    Either, AnnotatedMethods> build() {
        return Eithers.optionalList(validateAtLeastOneParameterInSuperCommand())
                ., AnnotatedMethods>>map(Either::left)
                .orElseGet(() -> right(new AnnotatedMethods(
                        step5.step4.namedOptions,
                        step5.positionalParameters,
                        repeatablePositionalParameters)));
    }

    private List validateAtLeastOneParameterInSuperCommand() {
        if (!step5.step4.step3.step2.sourceElement.isSuperCommand() ||
                !step5.positionalParameters.isEmpty()) {
            return List.of();
        }
        String message = "at least one positional parameter must be defined" +
                " when the superCommand attribute is set";
        return List.of(step5.step4.step3.step2.sourceElement.fail(message));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy