in gremlin-annotations/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/GremlinDslProcessor.java [128:218]
private void generateAnonymousTraversal(final Context ctx) throws IOException {
final TypeSpec.Builder anonymousClass = TypeSpec.classBuilder("__")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
// this class is just static methods - it should not be instantiated
anonymousClass.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.build());
// add start() method
anonymousClass.addMethod(MethodSpec.methodBuilder("start")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addTypeVariable(TypeVariableName.get("A"))
.addStatement("return new $N<>()", ctx.defaultTraversalClazz)
.returns(ParameterizedTypeName.get(ctx.traversalClassName, TypeVariableName.get("A"), TypeVariableName.get("A")))
.build());
// process the methods of the GremlinDsl annotated class
for (ExecutableElement templateMethod : findMethodsOfElement(ctx.annotatedDslType, null)) {
final Optional<GremlinDsl.AnonymousMethod> methodAnnotation = Optional.ofNullable(templateMethod.getAnnotation(GremlinDsl.AnonymousMethod.class));
final String methodName = templateMethod.getSimpleName().toString();
// either use the direct return type of the DSL specification or override it with specification from
// GremlinDsl.AnonymousMethod
final TypeName returnType = methodAnnotation.isPresent() && methodAnnotation.get().returnTypeParameters().length > 0 ?
getOverridenReturnTypeDefinition(ctx.traversalClassName, methodAnnotation.get().returnTypeParameters()) :
getReturnTypeDefinition(ctx.traversalClassName, templateMethod);
final MethodSpec.Builder methodToAdd = MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
.addExceptions(templateMethod.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()))
.returns(returnType);
// either use the method type parameter specified from the GremlinDsl.AnonymousMethod or just infer them
// from the DSL specification. "inferring" relies on convention and sometimes doesn't work for all cases.
final String startGeneric = methodAnnotation.isPresent() && methodAnnotation.get().methodTypeParameters().length > 0 ?
methodAnnotation.get().methodTypeParameters()[0] : "S";
if (methodAnnotation.isPresent() && methodAnnotation.get().methodTypeParameters().length > 0)
Stream.of(methodAnnotation.get().methodTypeParameters()).map(TypeVariableName::get).forEach(methodToAdd::addTypeVariable);
else {
templateMethod.getTypeParameters().forEach(tp -> methodToAdd.addTypeVariable(TypeVariableName.get(tp)));
// might have to deal with an "S" (in __ it's usually an "A") - how to make this less bound to that convention?
final List<? extends TypeMirror> returnTypeArguments = getTypeArguments(templateMethod);
returnTypeArguments.stream().filter(rtm -> rtm instanceof TypeVariable).forEach(rtm -> {
if (((TypeVariable) rtm).asElement().getSimpleName().contentEquals("S"))
methodToAdd.addTypeVariable(TypeVariableName.get(((TypeVariable) rtm).asElement().getSimpleName().toString()));
});
}
addMethodBody(methodToAdd, templateMethod, "return __.<" + startGeneric + ">start().$L(", ")", methodName);
anonymousClass.addMethod(methodToAdd.build());
}
// use methods from __ to template them into the DSL __
final Element anonymousTraversal = elementUtils.getTypeElement(__.class.getCanonicalName());
final Predicate<ExecutableElement> ignore = ee -> ee.getSimpleName().contentEquals("start");
for (ExecutableElement templateMethod : findMethodsOfElement(anonymousTraversal, ignore)) {
final String methodName = templateMethod.getSimpleName().toString();
final TypeName returnType = getReturnTypeDefinition(ctx.traversalClassName, templateMethod);
final MethodSpec.Builder methodToAdd = MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
.addExceptions(templateMethod.getThrownTypes().stream().map(TypeName::get).collect(Collectors.toList()))
.returns(returnType);
templateMethod.getTypeParameters().forEach(tp -> methodToAdd.addTypeVariable(TypeVariableName.get(tp)));
if (methodName.equals("__")) {
for (VariableElement param : templateMethod.getParameters()) {
methodToAdd.addParameter(ParameterSpec.get(param));
}
methodToAdd.varargs(true);
methodToAdd.addStatement("return inject(starts)", methodName);
} else {
if (templateMethod.getTypeParameters().isEmpty()) {
final List<? extends TypeMirror> types = getTypeArguments(templateMethod);
addMethodBody(methodToAdd, templateMethod, "return __.<$T>start().$L(", ")", types.get(0), methodName);
} else {
addMethodBody(methodToAdd, templateMethod, "return __.<A>start().$L(", ")", methodName);
}
}
anonymousClass.addMethod(methodToAdd.build());
}
final JavaFile traversalSourceJavaFile = JavaFile.builder(ctx.packageName, anonymousClass.build()).build();
traversalSourceJavaFile.writeTo(filer);
}