net.jbock.annotated.AnnotatedMethodsFactory 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 net.jbock.common.EnumName;
import net.jbock.common.Util;
import net.jbock.common.ValidationFailure;
import net.jbock.validate.ValidateScope;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.type.DeclaredType;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static io.jbock.util.Either.right;
import static io.jbock.util.Eithers.toValidListAll;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;
import static javax.lang.model.element.NestingKind.MEMBER;
import static net.jbock.common.Annotations.methodLevelAnnotations;
import static net.jbock.common.TypeTool.AS_DECLARED;
import static net.jbock.common.TypeTool.AS_TYPE_ELEMENT;
@ValidateScope
public class AnnotatedMethodsFactory {
private final Util util;
private final ExecutableElementsFinder executableElementsFinder;
@Inject
AnnotatedMethodsFactory(
Util util,
ExecutableElementsFinder executableElementsFinder) {
this.util = util;
this.executableElementsFinder = executableElementsFinder;
}
public Either, AnnotatedMethods> createAnnotatedMethods() {
return executableElementsFinder.findExecutableElements()
.flatMap(this::createAnnotatedMethods)
.map(AnnotatedMethodsBuilder.Step3::withNamedOptions)
.map(AnnotatedMethodsBuilder.Step4::withPositionalParameters)
.map(AnnotatedMethodsBuilder.Step5::withRepeatablePositionalParameters)
.flatMap(AnnotatedMethodsBuilder::build);
}
private Either, AnnotatedMethodsBuilder.Step3> createAnnotatedMethods(
AnnotatedMethodsBuilder.Step2 step) {
Map enumNames = step.enumNames();
return step.methods().stream()
.map(sourceMethod -> createAnnotatedMethod(sourceMethod,
enumNames.get(sourceMethod.simpleName())))
.collect(toValidListAll())
.map(step::withAnnotatedMethods);
}
private Either createAnnotatedMethod(
Executable sourceMethod,
EnumName enumName) {
ExecutableElement method = sourceMethod.method();
return util.checkNoDuplicateAnnotations(method, methodLevelAnnotations())
.>map(Either::left)
.orElseGet(() -> right(sourceMethod.annotatedMethod(enumName)))
.filter(this::checkAccessibleReturnType);
}
/* Left-Optional
*/
private Optional checkAccessibleReturnType(
AnnotatedMethod annotatedMethod) {
return AS_DECLARED.visit(annotatedMethod.returnType())
.filter(this::isInaccessible)
.map(type -> annotatedMethod.fail("inaccessible type: " +
util.typeToString(type)));
}
private boolean isInaccessible(DeclaredType declared) {
if (declared.asElement().getModifiers().contains(PRIVATE)) {
return true;
}
if (AS_TYPE_ELEMENT.visit(declared.asElement())
.filter(t -> t.getNestingKind() == MEMBER)
.filter(t -> !t.getModifiers().contains(STATIC))
.isPresent()) {
return true;
}
return declared.getTypeArguments().stream()
.map(AS_DECLARED::visit)
.flatMap(Optional::stream)
.anyMatch(this::isInaccessible);
}
}