private void generateAnonymousTraversal()

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);
    }