net.jbock.annotated.AnnotatedMethodsBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbock-compiler Show documentation
Show all versions of jbock-compiler Show documentation
jbock annotation processor
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));
}
}